Author SHA1 Message Date
_Neo_ e03fc738cd Refactor GetIcdPath 2026-09-13 21:38:20 -05:00
KeatonTheBot b6a9311394 Move JSON files to root directory 2026-09-13 21:38:20 -05:00
KeatonTheBot 3abe9a0285 Add icd.d JSON files for local, non-bundled builds 2026-09-13 21:38:20 -05:00
KeatonTheBot 6dc85e7f40 Add KosmicKrisp translation layer for macOS 26+
- Mesa 26.0 introduced KosmicKrisp, a Vulkan-on-Metal translation layer and the eventual successor to MoltenVK
2026-09-13 21:38:20 -05:00
60 changed files with 980 additions and 1843 deletions
+3 -2
View File
@@ -36,9 +36,11 @@
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.4-build6" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.4-build6" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.KosmicKrisp" Version="26.2.1-ryu.1" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.3-ryujinx.1" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.3-ryujinx.1" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" /> <PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.918.0" /> <PackageVersion Include="Ryujinx.SPB" Version="0.0.5-ryujinx.4" />
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" /> <PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" /> <PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
@@ -47,7 +49,6 @@
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
<PackageVersion Include="SkiaSharp" Version="3.119.4" /> <PackageVersion Include="SkiaSharp" Version="3.119.4" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.4" /> <PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.4" />
<PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="System.IO.Hashing" Version="10.0.12" /> <PackageVersion Include="System.IO.Hashing" Version="10.0.12" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
</ItemGroup> </ItemGroup>
@@ -48,7 +48,7 @@ def get_new_name(
return Path(os.path.join(output_directory, input_component)) return Path(os.path.join(output_directory, input_component))
def get_archs(dylib_path: Path) -> list[str]: def get_archs(dylib_path: Path) -> list[str]:
res = subprocess.check_output([LIPO, "-info", str(dylib_path)]).decode("utf-8") res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode("utf-8")
if res.startswith("Non-fat file"): if res.startswith("Non-fat file"):
return [res.split(":")[-1].strip()] return [res.split(":")[-1].strip()]
else: else:
+5 -1
View File
@@ -18,14 +18,18 @@ mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources"
cp "$PUBLISH_DIRECTORY/Ryujinx" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" cp "$PUBLISH_DIRECTORY/Ryujinx" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx" chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
# List all dylibs in PUBLISH_DIRECTORY
ls -la "$PUBLISH_DIRECTORY"/*.dylib
# Then all libraries # Then all libraries
cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" find "$PUBLISH_DIRECTORY" -name "*.dylib" -exec cp {} "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" \;
# Then resources # Then resources
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents" cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns" cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh" cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car" cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
cp -r vulkan "$APP_BUNDLE_DIRECTORY/Contents/Resources"
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources" cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo" echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
+4 -1
View File
@@ -47,7 +47,7 @@ EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
rm -rf "$TEMP_DIRECTORY" rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY" mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS) DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" -p:UseSharedCompilation=false --self-contained true $EXTRA_ARGS)
dotnet restore dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx dotnet build -c "$CONFIGURATION" src/Ryujinx
@@ -76,6 +76,9 @@ rm "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH"
# Make it libraries universal # Make it libraries universal
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_BUNDLE" "$X64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE" "**/*.dylib" python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_BUNDLE" "$X64_APP_BUNDLE" "$UNIVERSAL_APP_BUNDLE" "**/*.dylib"
# Copy arm64-only libraries to UNIVERSAL_APP_BUNDLE
cp "$ARM64_APP_BUNDLE/Contents/Frameworks/libvulkan_kosmickrisp.dylib" "$UNIVERSAL_APP_BUNDLE/Contents/Frameworks/libvulkan_kosmickrisp.dylib"
if ! [ -x "$(command -v lipo)" ]; if ! [ -x "$(command -v lipo)" ];
then then
if ! [ -x "$(command -v llvm-lipo-17)" ]; if ! [ -x "$(command -v llvm-lipo-17)" ];
@@ -0,0 +1,8 @@
{
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "./libMoltenVK.dylib",
"api_version" : "1.4.0",
"is_portability_driver" : true
}
}
@@ -0,0 +1,8 @@
{
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "../../../Frameworks/libMoltenVK.dylib",
"api_version" : "1.4.0",
"is_portability_driver" : true
}
}
@@ -0,0 +1,7 @@
{
"ICD": {
"api_version": "1.3.0",
"library_path": "./libvulkan_kosmickrisp.dylib"
},
"file_format_version": "1.0.1"
}
@@ -0,0 +1,7 @@
{
"ICD": {
"api_version": "1.3.0",
"library_path": "../../../Frameworks/libvulkan_kosmickrisp.dylib"
},
"file_format_version": "1.0.1"
}
+4
View File
@@ -2,6 +2,7 @@
<configuration> <configuration>
<packageSources> <packageSources>
<clear /> <clear />
<add key="local" value="nuget" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. --> <!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/packages/projects/nuget/index.json" /> <add key="LibHacAlpha" value="https://git.ryujinx.app/api/packages/projects/nuget/index.json" />
@@ -10,6 +11,9 @@
<packageSourceMapping> <packageSourceMapping>
<!-- key value for <packageSource> should match key values from <packageSources> element --> <!-- key value for <packageSource> should match key values from <packageSources> element -->
<!-- These are defined and .NET still yells about multiple package sources with no mappings. Not sure what to do, this is in the docs lol --> <!-- These are defined and .NET still yells about multiple package sources with no mappings. Not sure what to do, this is in the docs lol -->
<packageSource key="local">
<package pattern="Ryujinx.Graphics.Vulkan.KosmicKrisp" />
</packageSource>
<packageSource key="nuget.org"> <packageSource key="nuget.org">
<package pattern="*" /> <package pattern="*" />
</packageSource> </packageSource>
@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;
namespace Ryujinx.Common.Configuration
{
[JsonConverter(typeof(JsonStringEnumConverter<TranslationLayer>))]
public enum TranslationLayer
{
MoltenVK,
KosmicKrisp,
}
}
-12
View File
@@ -51,10 +51,6 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsViewportSwizzle; public readonly bool SupportsViewportSwizzle;
public readonly bool SupportsIndirectParameters; public readonly bool SupportsIndirectParameters;
public readonly bool SupportsDepthClipControl; public readonly bool SupportsDepthClipControl;
public readonly bool SupportsExtendedDynamicState;
public readonly bool SupportsExtendedDynamicState2;
public readonly bool SupportsLogicOpDynamicState;
public readonly bool SupportsPatchControlPointsDynamicState;
public readonly int UniformBufferSetIndex; public readonly int UniformBufferSetIndex;
public readonly int StorageBufferSetIndex; public readonly int StorageBufferSetIndex;
@@ -124,10 +120,6 @@ namespace Ryujinx.Graphics.GAL
bool supportsViewportSwizzle, bool supportsViewportSwizzle,
bool supportsIndirectParameters, bool supportsIndirectParameters,
bool supportsDepthClipControl, bool supportsDepthClipControl,
bool supportsExtendedDynamicState,
bool supportsExtendedDynamicState2,
bool supportsLogicOpDynamicState,
bool supportsPatchControlPointsDynamicState,
int uniformBufferSetIndex, int uniformBufferSetIndex,
int storageBufferSetIndex, int storageBufferSetIndex,
int textureSetIndex, int textureSetIndex,
@@ -191,10 +183,6 @@ namespace Ryujinx.Graphics.GAL
SupportsViewportSwizzle = supportsViewportSwizzle; SupportsViewportSwizzle = supportsViewportSwizzle;
SupportsIndirectParameters = supportsIndirectParameters; SupportsIndirectParameters = supportsIndirectParameters;
SupportsDepthClipControl = supportsDepthClipControl; SupportsDepthClipControl = supportsDepthClipControl;
SupportsExtendedDynamicState = supportsExtendedDynamicState;
SupportsExtendedDynamicState2 = supportsExtendedDynamicState2;
SupportsLogicOpDynamicState = supportsLogicOpDynamicState;
SupportsPatchControlPointsDynamicState = supportsPatchControlPointsDynamicState;
UniformBufferSetIndex = uniformBufferSetIndex; UniformBufferSetIndex = uniformBufferSetIndex;
StorageBufferSetIndex = storageBufferSetIndex; StorageBufferSetIndex = storageBufferSetIndex;
TextureSetIndex = textureSetIndex; TextureSetIndex = textureSetIndex;
-1
View File
@@ -2,7 +2,6 @@ namespace Ryujinx.Graphics.GAL
{ {
public enum Face public enum Face
{ {
None = 0,
Front = 0x404, Front = 0x404,
Back = 0x405, Back = 0x405,
FrontAndBack = 0x408, FrontAndBack = 0x408,
+7 -7
View File
@@ -50,9 +50,9 @@ namespace Ryujinx.Graphics.GAL
void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp); void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp);
void SetDepthClamp(bool clamp); void SetDepthClamp(bool clamp);
void SetDepthMode(DepthMode mode); void SetDepthMode(DepthMode mode);
void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true); void SetDepthTest(DepthTestDescriptor depthTest);
void SetFaceCulling(Face face); void SetFaceCulling(bool enable, Face face);
void SetFrontFace(FrontFace frontFace); void SetFrontFace(FrontFace frontFace);
@@ -75,16 +75,16 @@ namespace Ryujinx.Graphics.GAL
void SetPrimitiveRestart(bool enable, int index); void SetPrimitiveRestart(bool enable, int index);
void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true); void SetPrimitiveTopology(PrimitiveTopology topology);
void SetProgram(IProgram program, bool signalChange = true); void SetProgram(IProgram program);
void SetRasterizerDiscard(bool discard); void SetRasterizerDiscard(bool discard);
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask, bool signalChange = true); void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
void SetRenderTargets(Span<ITexture> colors, ITexture depthStencil); void SetRenderTargets(Span<ITexture> colors, ITexture depthStencil);
void SetScissors(ReadOnlySpan<Rectangle<int>> regions, bool signalChange = true); void SetScissors(ReadOnlySpan<Rectangle<int>> regions);
void SetStencilTest(StencilTestDescriptor stencilTest); void SetStencilTest(StencilTestDescriptor stencilTest);
@@ -102,7 +102,7 @@ namespace Ryujinx.Graphics.GAL
void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs); void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers); void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true); void SetViewports(ReadOnlySpan<Viewport> viewports);
void TextureBarrier(); void TextureBarrier();
void TextureBarrierTiled(); void TextureBarrierTiled();
@@ -3,16 +3,18 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
struct SetFaceCullingCommand : IGALCommand, IGALCommand<SetFaceCullingCommand> struct SetFaceCullingCommand : IGALCommand, IGALCommand<SetFaceCullingCommand>
{ {
public readonly CommandType CommandType => CommandType.SetFaceCulling; public readonly CommandType CommandType => CommandType.SetFaceCulling;
private bool _enable;
private Face _face; private Face _face;
public void Set(Face face) public void Set(bool enable, Face face)
{ {
_enable = enable;
_face = face; _face = face;
} }
public static void Run(ref SetFaceCullingCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetFaceCullingCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
renderer.Pipeline.SetFaceCulling(command._face); renderer.Pipeline.SetFaceCulling(command._enable, command._face);
} }
} }
} }
@@ -158,15 +158,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true) public unsafe void SetDepthTest(DepthTestDescriptor depthTest)
{ {
_renderer.New<SetDepthTestCommand>()->Set(depthTest); _renderer.New<SetDepthTestCommand>()->Set(depthTest);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetFaceCulling(Face face) public unsafe void SetFaceCulling(bool enable, Face face)
{ {
_renderer.New<SetFaceCullingCommand>()->Set(face); _renderer.New<SetFaceCullingCommand>()->Set(enable, face);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
@@ -242,13 +242,13 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true) public unsafe void SetPrimitiveTopology(PrimitiveTopology topology)
{ {
_renderer.New<SetPrimitiveTopologyCommand>()->Set(topology); _renderer.New<SetPrimitiveTopologyCommand>()->Set(topology);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetProgram(IProgram program, bool signalChange = true) public unsafe void SetProgram(IProgram program)
{ {
_renderer.New<SetProgramCommand>()->Set(Ref(program)); _renderer.New<SetProgramCommand>()->Set(Ref(program));
_renderer.QueueCommand(); _renderer.QueueCommand();
@@ -260,7 +260,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask, bool signalChange = true) public unsafe void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
{ {
_renderer.New<SetRenderTargetColorMasksCommand>()->Set(_renderer.CopySpan(componentMask)); _renderer.New<SetRenderTargetColorMasksCommand>()->Set(_renderer.CopySpan(componentMask));
_renderer.QueueCommand(); _renderer.QueueCommand();
@@ -275,7 +275,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetScissors(ReadOnlySpan<Rectangle<int>> scissors, bool signalChange = true) public unsafe void SetScissors(ReadOnlySpan<Rectangle<int>> scissors)
{ {
_renderer.New<SetScissorsCommand>()->Set(_renderer.CopySpan(scissors)); _renderer.New<SetScissorsCommand>()->Set(_renderer.CopySpan(scissors));
_renderer.QueueCommand(); _renderer.QueueCommand();
@@ -341,7 +341,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public unsafe void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true) public unsafe void SetViewports(ReadOnlySpan<Viewport> viewports)
{ {
_renderer.New<SetViewportsCommand>()->Set(_renderer.CopySpan(viewports)); _renderer.New<SetViewportsCommand>()->Set(_renderer.CopySpan(viewports));
_renderer.QueueCommand(); _renderer.QueueCommand();
@@ -51,12 +51,11 @@ namespace Ryujinx.Graphics.GAL
public StencilTestDescriptor StencilTest; public StencilTestDescriptor StencilTest;
public FrontFace FrontFace; public FrontFace FrontFace;
public Face CullMode; public Face CullMode;
public bool CullEnable;
public PolygonModeMask BiasEnable; public PolygonModeMask BiasEnable;
public bool AlphaToCoverageEnable; public float LineWidth;
public bool AlphaToOneEnable;
// TODO: Polygon mode. // TODO: Polygon mode.
public bool DepthClampEnable; public bool DepthClampEnable;
public bool RasterizerDiscard; public bool RasterizerDiscard;
@@ -64,9 +63,6 @@ namespace Ryujinx.Graphics.GAL
public bool PrimitiveRestartEnable; public bool PrimitiveRestartEnable;
public uint PatchControlPoints; public uint PatchControlPoints;
public float DepthBiasUnits;
public float DepthBiasFactor;
public DepthMode DepthMode; public DepthMode DepthMode;
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs) public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
@@ -861,9 +861,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0); enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
_pipeline.BiasEnable = enables; _pipeline.BiasEnable = enables;
_pipeline.DepthBiasUnits = units / 2f;
_pipeline.DepthBiasFactor = factor;
_context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp); _context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
} }
@@ -1037,6 +1034,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
float width = _state.State.LineWidthSmooth; float width = _state.State.LineWidthSmooth;
bool smooth = _state.State.LineSmoothEnable; bool smooth = _state.State.LineSmoothEnable;
_pipeline.LineWidth = width;
_context.Renderer.Pipeline.SetLineParameters(width, smooth); _context.Renderer.Pipeline.SetLineParameters(width, smooth);
} }
@@ -1218,16 +1216,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
YControl yControl = _state.State.YControl; YControl yControl = _state.State.YControl;
FaceState face = _state.State.FaceState; FaceState face = _state.State.FaceState;
if (face.CullEnable) _pipeline.CullEnable = face.CullEnable;
{ _pipeline.CullMode = face.CullFace;
_pipeline.CullMode = face.CullFace; _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
_context.Renderer.Pipeline.SetFaceCulling(face.CullFace);
}
else
{
_pipeline.CullMode = Face.None;
_context.Renderer.Pipeline.SetFaceCulling(Face.None);
}
UpdateFrontFace(yControl, face.FrontFace); UpdateFrontFace(yControl, face.FrontFace);
} }
@@ -1425,8 +1416,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
bool alphaToCoverageEnable = (_state.State.MultisampleControl & 1) != 0; bool alphaToCoverageEnable = (_state.State.MultisampleControl & 1) != 0;
bool alphaToOneEnable = (_state.State.MultisampleControl & 0x10) != 0; bool alphaToOneEnable = (_state.State.MultisampleControl & 0x10) != 0;
_pipeline.AlphaToCoverageEnable = alphaToCoverageEnable;
_pipeline.AlphaToOneEnable = alphaToOneEnable;
_context.Renderer.Pipeline.SetMultisampleState(new MultisampleDescriptor( _context.Renderer.Pipeline.SetMultisampleState(new MultisampleDescriptor(
alphaToCoverageEnable, alphaToCoverageEnable,
_state.State.AlphaToCoverageDitherEnable, _state.State.AlphaToCoverageDitherEnable,
@@ -22,8 +22,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private readonly CancellationToken _cancellationToken; private readonly CancellationToken _cancellationToken;
private readonly Action<ShaderCacheState, int, int> _stateChangeCallback; private readonly Action<ShaderCacheState, int, int> _stateChangeCallback;
private readonly HashSet<ProgramPipelineState> _pipelineStateSet = new();
/// <summary> /// <summary>
/// Indicates if the cache should be loaded. /// Indicates if the cache should be loaded.
/// </summary> /// </summary>
@@ -234,7 +232,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
for (int index = 0; index < ThreadCount; index++) for (int index = 0; index < ThreadCount; index++)
{ {
workThreads[index] = new Thread(ProcessAsyncQueue) { Name = $"GPU.AsyncTranslationThread.{index}", }; workThreads[index] = new Thread(ProcessAsyncQueue)
{
Name = $"GPU.AsyncTranslationThread.{index}",
};
} }
int programCount = _hostStorage.GetProgramCount(); int programCount = _hostStorage.GetProgramCount();
@@ -304,8 +305,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
using DiskCacheOutputStreams streams = _hostStorage.GetOutputStreams(_context); using DiskCacheOutputStreams streams = _hostStorage.GetOutputStreams(_context);
int packagedShaders = 0; int packagedShaders = 0;
ProgramPipelineState currentPipelineState = default;
foreach (KeyValuePair<int, (CachedShaderProgram, byte[])> kv in _programList) foreach (KeyValuePair<int, (CachedShaderProgram, byte[])> kv in _programList)
{ {
if (!Active) if (!Active)
@@ -315,53 +314,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
(CachedShaderProgram program, byte[] binaryCode) = kv.Value; (CachedShaderProgram program, byte[] binaryCode) = kv.Value;
if (program.SpecializationState.PipelineState.HasValue && _context.Capabilities.SupportsExtendedDynamicState) _hostStorage.AddShader(_context, program, binaryCode, streams);
{
currentPipelineState = program.SpecializationState.PipelineState.Value;
if (_context.Capabilities.SupportsExtendedDynamicState) _stateChangeCallback(ShaderCacheState.Packaging, ++packagedShaders, _programList.Count);
{
currentPipelineState.StencilTest = default;
currentPipelineState.CullMode = 0;
currentPipelineState.FrontFace = 0;
currentPipelineState.DepthTest = default;
currentPipelineState.Topology = ConvertToClass(currentPipelineState.Topology);
}
if (_context.Capabilities.SupportsExtendedDynamicState2)
{
currentPipelineState.PrimitiveRestartEnable = false;
currentPipelineState.BiasEnable = 0;
currentPipelineState.RasterizerDiscard = false;
}
if (_context.Capabilities.SupportsLogicOpDynamicState)
{
currentPipelineState.LogicOp = 0;
}
if (_context.Capabilities.SupportsPatchControlPointsDynamicState)
{
currentPipelineState.PatchControlPoints = 0;
}
}
if (!_pipelineStateSet.Contains(currentPipelineState) ||
!_context.Capabilities.SupportsExtendedDynamicState ||
!program.SpecializationState.PipelineState.HasValue)
{
_hostStorage.AddShader(_context, program, binaryCode, streams);
_stateChangeCallback(ShaderCacheState.Packaging, ++packagedShaders, _programList.Count);
if (_context.Capabilities.SupportsExtendedDynamicState)
{
_pipelineStateSet.Add(currentPipelineState);
}
}
} }
Logger.Info?.Print(LogClass.Gpu, $"Rebuilt {packagedShaders} shaders successfully.");
Logger.Info?.Print(LogClass.Gpu, $"Rebuilt {_programList.Count} shaders successfully.");
} }
else else
{ {
@@ -385,29 +343,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
_stateChangeCallback(ShaderCacheState.Loaded, programCount, programCount); _stateChangeCallback(ShaderCacheState.Loaded, programCount, programCount);
} }
private PrimitiveTopology ConvertToClass(PrimitiveTopology topology)
{
return topology switch
{
PrimitiveTopology.Points => PrimitiveTopology.Points,
PrimitiveTopology.Lines or
PrimitiveTopology.LineStrip or
PrimitiveTopology.LinesAdjacency or
PrimitiveTopology.LineStripAdjacency => PrimitiveTopology.Lines,
PrimitiveTopology.Triangles or
PrimitiveTopology.TriangleStrip or
PrimitiveTopology.TriangleFan or
PrimitiveTopology.TrianglesAdjacency or
PrimitiveTopology.TriangleStripAdjacency or
PrimitiveTopology.Polygon => PrimitiveTopology.TriangleStrip,
PrimitiveTopology.Patches => PrimitiveTopology.Patches,
PrimitiveTopology.Quads => PrimitiveTopology.Quads,
PrimitiveTopology.QuadStrip => PrimitiveTopology.QuadStrip,
PrimitiveTopology.LineLoop => PrimitiveTopology.LineLoop,
_ => PrimitiveTopology.TriangleStrip,
};
}
/// <summary> /// <summary>
/// Enqueues a host program for compilation. /// Enqueues a host program for compilation.
/// </summary> /// </summary>
@@ -193,10 +193,6 @@ namespace Ryujinx.Graphics.OpenGL
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle, supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters, supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
supportsDepthClipControl: true, supportsDepthClipControl: true,
supportsExtendedDynamicState: false,
supportsExtendedDynamicState2: false,
supportsLogicOpDynamicState: false,
supportsPatchControlPointsDynamicState: false,
uniformBufferSetIndex: 0, uniformBufferSetIndex: 0,
storageBufferSetIndex: 1, storageBufferSetIndex: 1,
textureSetIndex: 2, textureSetIndex: 2,
+9 -9
View File
@@ -898,7 +898,7 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true) public void SetDepthTest(DepthTestDescriptor depthTest)
{ {
if (depthTest.TestEnable) if (depthTest.TestEnable)
{ {
@@ -915,11 +915,11 @@ namespace Ryujinx.Graphics.OpenGL
_depthTestEnable = depthTest.TestEnable; _depthTestEnable = depthTest.TestEnable;
} }
public void SetFaceCulling(Face face) public void SetFaceCulling(bool enable, Face face)
{ {
_cullEnable = face != Face.None; _cullEnable = enable;
if (!_cullEnable) if (!enable)
{ {
GL.Disable(EnableCap.CullFace); GL.Disable(EnableCap.CullFace);
return; return;
@@ -1107,12 +1107,12 @@ namespace Ryujinx.Graphics.OpenGL
GL.Enable(EnableCap.PrimitiveRestart); GL.Enable(EnableCap.PrimitiveRestart);
} }
public void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true) public void SetPrimitiveTopology(PrimitiveTopology topology)
{ {
_primitiveType = topology.Convert(); _primitiveType = topology.Convert();
} }
public void SetProgram(IProgram program, bool signalChange = true) public void SetProgram(IProgram program)
{ {
Program prg = (Program)program; Program prg = (Program)program;
@@ -1154,7 +1154,7 @@ namespace Ryujinx.Graphics.OpenGL
_rasterizerDiscard = discard; _rasterizerDiscard = discard;
} }
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks, bool signalChange = true) public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
{ {
_componentMasks = 0; _componentMasks = 0;
@@ -1195,7 +1195,7 @@ namespace Ryujinx.Graphics.OpenGL
_framebuffer.SetDrawBuffers(colors.Length); _framebuffer.SetDrawBuffers(colors.Length);
} }
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions, bool signalChange = true) public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
{ {
int count = Math.Min(regions.Length, Constants.MaxViewports); int count = Math.Min(regions.Length, Constants.MaxViewports);
@@ -1388,7 +1388,7 @@ namespace Ryujinx.Graphics.OpenGL
_vertexArray.SetVertexBuffers(vertexBuffers); _vertexArray.SetVertexBuffers(vertexBuffers);
} }
public void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true) public void SetViewports(ReadOnlySpan<Viewport> viewports)
{ {
Array.Resize(ref _viewportArray, viewports.Length * 4); Array.Resize(ref _viewportArray, viewports.Length * 4);
Array.Resize(ref _depthRangeArray, viewports.Length * 2); Array.Resize(ref _depthRangeArray, viewports.Length * 2);
@@ -255,8 +255,8 @@ namespace Ryujinx.Graphics.Vulkan.Effects
scissors[0] = new Rectangle<int>(0, 0, texture.Width, texture.Height); scissors[0] = new Rectangle<int>(0, 0, texture.Width, texture.Height);
_pipeline.SetRenderTarget(texture, (uint)texture.Width, (uint)texture.Height, false); _pipeline.SetRenderTarget(texture, (uint)texture.Width, (uint)texture.Height);
_pipeline.SetRenderTargetColorMasks(colorMasks, false); _pipeline.SetRenderTargetColorMasks(colorMasks);
_pipeline.SetScissors(scissors); _pipeline.SetScissors(scissors);
_pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f)); _pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
} }
@@ -238,7 +238,6 @@ namespace Ryujinx.Graphics.Vulkan
Face.Back => CullModeFlags.BackBit, Face.Back => CullModeFlags.BackBit,
Face.Front => CullModeFlags.FrontBit, Face.Front => CullModeFlags.FrontBit,
Face.FrontAndBack => CullModeFlags.FrontAndBack, Face.FrontAndBack => CullModeFlags.FrontAndBack,
Face.None => CullModeFlags.None,
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.BackBit), _ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.BackBit),
}; };
} }
@@ -311,25 +310,6 @@ namespace Ryujinx.Graphics.Vulkan
}; };
} }
public static PrimitiveTopology ConvertToClass(this PrimitiveTopology topology)
{
return topology switch
{
PrimitiveTopology.PointList => PrimitiveTopology.PointList,
PrimitiveTopology.LineList or
PrimitiveTopology.LineStrip or
PrimitiveTopology.LineListWithAdjacency or
PrimitiveTopology.LineStripWithAdjacency => PrimitiveTopology.LineList,
PrimitiveTopology.TriangleList or
PrimitiveTopology.TriangleStrip or
PrimitiveTopology.TriangleFan or
PrimitiveTopology.TriangleListWithAdjacency or
PrimitiveTopology.TriangleStripWithAdjacency => PrimitiveTopology.TriangleStrip,
PrimitiveTopology.PatchList => PrimitiveTopology.PatchList,
_ => LogInvalidAndReturn(topology, nameof(PrimitiveTopology), PrimitiveTopology.TriangleStrip),
};
}
public static StencilOp Convert(this GAL.StencilOp op) public static StencilOp Convert(this GAL.StencilOp op)
{ {
return op switch return op switch
@@ -31,7 +31,6 @@ namespace Ryujinx.Graphics.Vulkan
public readonly bool SupportsShaderStorageImageMultisample; public readonly bool SupportsShaderStorageImageMultisample;
public readonly bool SupportsConditionalRendering; public readonly bool SupportsConditionalRendering;
public readonly bool SupportsExtendedDynamicState; public readonly bool SupportsExtendedDynamicState;
public readonly PhysicalDeviceExtendedDynamicState2FeaturesEXT SupportsExtendedDynamicState2;
public readonly bool SupportsMultiView; public readonly bool SupportsMultiView;
public readonly bool SupportsNullDescriptors; public readonly bool SupportsNullDescriptors;
public readonly bool SupportsPushDescriptors; public readonly bool SupportsPushDescriptors;
@@ -47,7 +46,6 @@ namespace Ryujinx.Graphics.Vulkan
public readonly bool SupportsViewportArray2; public readonly bool SupportsViewportArray2;
public readonly bool SupportsHostImportedMemory; public readonly bool SupportsHostImportedMemory;
public readonly bool SupportsDepthClipControl; public readonly bool SupportsDepthClipControl;
public readonly bool SupportsWideLines;
public readonly bool SupportsAttachmentFeedbackLoop; public readonly bool SupportsAttachmentFeedbackLoop;
public readonly bool SupportsDynamicAttachmentFeedbackLoop; public readonly bool SupportsDynamicAttachmentFeedbackLoop;
public readonly uint SubgroupSize; public readonly uint SubgroupSize;
@@ -56,7 +54,6 @@ namespace Ryujinx.Graphics.Vulkan
public readonly uint VertexBufferAlignment; public readonly uint VertexBufferAlignment;
public readonly uint SubTexelPrecisionBits; public readonly uint SubTexelPrecisionBits;
public readonly ulong MinResourceAlignment; public readonly ulong MinResourceAlignment;
public readonly uint MaxTessellationPatchSize;
public readonly ulong MinTexelBufferAlignment; public readonly ulong MinTexelBufferAlignment;
public HardwareCapabilities( public HardwareCapabilities(
@@ -75,8 +72,6 @@ namespace Ryujinx.Graphics.Vulkan
bool supportsShaderStorageImageMultisample, bool supportsShaderStorageImageMultisample,
bool supportsConditionalRendering, bool supportsConditionalRendering,
bool supportsExtendedDynamicState, bool supportsExtendedDynamicState,
PhysicalDeviceExtendedDynamicState2FeaturesEXT supportsExtendedDynamicState2,
uint maxTessellationPatchSize,
bool supportsMultiView, bool supportsMultiView,
bool supportsNullDescriptors, bool supportsNullDescriptors,
bool supportsPushDescriptors, bool supportsPushDescriptors,
@@ -92,7 +87,6 @@ namespace Ryujinx.Graphics.Vulkan
bool supportsViewportArray2, bool supportsViewportArray2,
bool supportsHostImportedMemory, bool supportsHostImportedMemory,
bool supportsDepthClipControl, bool supportsDepthClipControl,
bool supportsWideLines,
bool supportsAttachmentFeedbackLoop, bool supportsAttachmentFeedbackLoop,
bool supportsDynamicAttachmentFeedbackLoop, bool supportsDynamicAttachmentFeedbackLoop,
uint subgroupSize, uint subgroupSize,
@@ -118,8 +112,6 @@ namespace Ryujinx.Graphics.Vulkan
SupportsShaderStorageImageMultisample = supportsShaderStorageImageMultisample; SupportsShaderStorageImageMultisample = supportsShaderStorageImageMultisample;
SupportsConditionalRendering = supportsConditionalRendering; SupportsConditionalRendering = supportsConditionalRendering;
SupportsExtendedDynamicState = supportsExtendedDynamicState; SupportsExtendedDynamicState = supportsExtendedDynamicState;
SupportsExtendedDynamicState2 = supportsExtendedDynamicState2;
MaxTessellationPatchSize = maxTessellationPatchSize;
SupportsMultiView = supportsMultiView; SupportsMultiView = supportsMultiView;
SupportsNullDescriptors = supportsNullDescriptors; SupportsNullDescriptors = supportsNullDescriptors;
SupportsPushDescriptors = supportsPushDescriptors; SupportsPushDescriptors = supportsPushDescriptors;
@@ -135,7 +127,6 @@ namespace Ryujinx.Graphics.Vulkan
SupportsViewportArray2 = supportsViewportArray2; SupportsViewportArray2 = supportsViewportArray2;
SupportsHostImportedMemory = supportsHostImportedMemory; SupportsHostImportedMemory = supportsHostImportedMemory;
SupportsDepthClipControl = supportsDepthClipControl; SupportsDepthClipControl = supportsDepthClipControl;
SupportsWideLines = supportsWideLines;
SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop; SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop;
SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop; SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop;
SubgroupSize = subgroupSize; SubgroupSize = subgroupSize;
+14 -14
View File
@@ -406,20 +406,20 @@ namespace Ryujinx.Graphics.Vulkan
if (dstIsDepthOrStencil) if (dstIsDepthOrStencil)
{ {
_pipeline.SetProgram(src.Info.Target.IsMultisample ? _programDepthBlitMs : _programDepthBlit, false); _pipeline.SetProgram(src.Info.Target.IsMultisample ? _programDepthBlitMs : _programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always), false); _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
} }
else if (src.Info.Target.IsMultisample) else if (src.Info.Target.IsMultisample)
{ {
_pipeline.SetProgram(_programColorBlitMs, false); _pipeline.SetProgram(_programColorBlitMs);
} }
else if (clearAlpha) else if (clearAlpha)
{ {
_pipeline.SetProgram(_programColorBlitClearAlpha, false); _pipeline.SetProgram(_programColorBlitClearAlpha);
} }
else else
{ {
_pipeline.SetProgram(_programColorBlit, false); _pipeline.SetProgram(_programColorBlit);
} }
int dstWidth = dst.Width; int dstWidth = dst.Width;
@@ -434,7 +434,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f)); _pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
} }
_pipeline.SetViewports(viewports, false); _pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0); _pipeline.Draw(4, 1, 0, 0);
@@ -566,12 +566,12 @@ namespace Ryujinx.Graphics.Vulkan
if (isDepth) if (isDepth)
{ {
_pipeline.SetProgram(src.Info.Target.IsMultisample ? _programDepthBlitMs : _programDepthBlit, false); _pipeline.SetProgram(src.Info.Target.IsMultisample ? _programDepthBlitMs : _programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always)); _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
} }
else else
{ {
_pipeline.SetProgram(src.Info.Target.IsMultisample ? _programStencilBlitMs : _programStencilBlit, false); _pipeline.SetProgram(src.Info.Target.IsMultisample ? _programStencilBlitMs : _programStencilBlit);
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true)); _pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
} }
@@ -771,8 +771,8 @@ namespace Ryujinx.Graphics.Vulkan
0f, 0f,
1f); 1f);
pipeline.SetProgram(_programColorBlit, false); pipeline.SetProgram(_programColorBlit);
pipeline.SetViewports(viewports, false); pipeline.SetViewports(viewports);
pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
pipeline.Draw(4, 1, 0, 0); pipeline.Draw(4, 1, 0, 0);
@@ -1229,7 +1229,7 @@ namespace Ryujinx.Graphics.Vulkan
TextureView srcView = Create2DLayerView(src, srcLayer + z, 0); TextureView srcView = Create2DLayerView(src, srcLayer + z, 0);
TextureView dstView = Create2DLayerView(dst, dstLayer + z, 0); TextureView dstView = Create2DLayerView(dst, dstLayer + z, 0);
_pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height, false); _pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height);
CopyMSDraw(srcView, aspectFlags, fromMS: false); CopyMSDraw(srcView, aspectFlags, fromMS: false);
@@ -1246,7 +1246,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
else else
{ {
_pipeline.SetProgram(_programColorDrawToMs, false); _pipeline.SetProgram(_programColorDrawToMs);
Format format = GetFormat(src.Info.BytesPerPixel); Format format = GetFormat(src.Info.BytesPerPixel);
VkFormat vkFormat = FormatTable.GetFormat(format); VkFormat vkFormat = FormatTable.GetFormat(format);
@@ -1323,12 +1323,12 @@ namespace Ryujinx.Graphics.Vulkan
if (isDepth) if (isDepth)
{ {
_pipeline.SetProgram(fromMS ? _programDepthDrawToNonMs : _programDepthDrawToMs, false); _pipeline.SetProgram(fromMS ? _programDepthDrawToNonMs : _programDepthDrawToMs);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always)); _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
} }
else else
{ {
_pipeline.SetProgram(fromMS ? _programStencilDrawToNonMs : _programStencilDrawToMs, false); _pipeline.SetProgram(fromMS ? _programStencilDrawToNonMs : _programStencilDrawToMs);
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true)); _pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
} }
@@ -1,104 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Vulkan.MoltenVK
{
enum MVKConfigLogLevel
{
None = 0,
Error = 1,
Warning = 2,
Info = 3,
Debug = 4,
}
enum MVKConfigTraceVulkanCalls
{
None = 0,
Enter = 1,
EnterExit = 2,
Duration = 3,
}
enum MVKConfigAutoGPUCaptureScope
{
None = 0,
Device = 1,
Frame = 2,
}
[Flags]
enum MVKConfigAdvertiseExtensions
{
All = 0x00000001,
MoltenVK = 0x00000002,
WSI = 0x00000004,
Portability = 0x00000008,
}
enum MVKVkSemaphoreSupportStyle
{
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0,
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1,
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2,
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3,
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF,
}
readonly struct Bool32
{
uint Value { get; }
public Bool32(uint value)
{
Value = value;
}
public Bool32(bool value)
{
Value = value ? 1u : 0u;
}
public static implicit operator bool(Bool32 val) => val.Value == 1;
public static implicit operator Bool32(bool val) => new(val);
}
[StructLayout(LayoutKind.Sequential)]
struct MVKConfiguration
{
public Bool32 DebugMode;
public Bool32 ShaderConversionFlipVertexY;
public Bool32 SynchronousQueueSubmits;
public Bool32 PrefillMetalCommandBuffers;
public uint MaxActiveMetalCommandBuffersPerQueue;
public Bool32 SupportLargeQueryPools;
public Bool32 PresentWithCommandBuffer;
public Bool32 SwapchainMagFilterUseNearest;
public ulong MetalCompileTimeout;
public Bool32 PerformanceTracking;
public uint PerformanceLoggingFrameCount;
public Bool32 DisplayWatermark;
public Bool32 SpecializedQueueFamilies;
public Bool32 SwitchSystemGPU;
public Bool32 FullImageViewSwizzle;
public uint DefaultGPUCaptureScopeQueueFamilyIndex;
public uint DefaultGPUCaptureScopeQueueIndex;
public Bool32 FastMathEnabled;
public MVKConfigLogLevel LogLevel;
public MVKConfigTraceVulkanCalls TraceVulkanCalls;
public Bool32 ForceLowPowerGPU;
public Bool32 SemaphoreUseMTLFence;
public MVKVkSemaphoreSupportStyle SemaphoreSupportStyle;
public MVKConfigAutoGPUCaptureScope AutoGPUCaptureScope;
public nint AutoGPUCaptureOutputFilepath;
public Bool32 Texture1DAs2D;
public Bool32 PreallocateDescriptors;
public Bool32 UseCommandPooling;
public Bool32 UseMTLHeap;
public Bool32 LogActivityPerformanceInline;
public uint ApiVersionToAdvertise;
public MVKConfigAdvertiseExtensions AdvertiseExtensions;
public Bool32 ResumeLostDevice;
public Bool32 UseMetalArgumentBuffers;
}
}
@@ -1,51 +0,0 @@
using Silk.NET.Core.Loader;
using Silk.NET.Vulkan;
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Vulkan.MoltenVK
{
[SupportedOSPlatform("macos")]
public static partial class MVKInitialization
{
private const string VulkanLib = "libvulkan.dylib";
[LibraryImport("libMoltenVK.dylib")]
private static partial Result vkGetMoltenVKConfigurationMVK(nint unusedInstance, out MVKConfiguration config, in nint configSize);
[LibraryImport("libMoltenVK.dylib")]
private static partial Result vkSetMoltenVKConfigurationMVK(nint unusedInstance, in MVKConfiguration config, in nint configSize);
public static void Initialize()
{
IntPtr configSize = (nint)Marshal.SizeOf<MVKConfiguration>();
vkGetMoltenVKConfigurationMVK(nint.Zero, out MVKConfiguration config, configSize);
config.UseMetalArgumentBuffers = true;
config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE;
config.SynchronousQueueSubmits = false;
config.ResumeLostDevice = true;
vkSetMoltenVKConfigurationMVK(nint.Zero, config, configSize);
}
private static string[] Resolver(string path)
{
if (path.EndsWith(VulkanLib))
{
path = path[..^VulkanLib.Length] + "libMoltenVK.dylib";
return [path];
}
return [];
}
public static void InitializeResolver()
{
((DefaultPathResolver)PathResolver.Default).Resolvers.Insert(0, Resolver);
}
}
}
+91 -335
View File
@@ -76,7 +76,6 @@ namespace Ryujinx.Graphics.Vulkan
private readonly BufferState[] _transformFeedbackBuffers; private readonly BufferState[] _transformFeedbackBuffers;
private readonly VertexBufferState[] _vertexBuffers; private readonly VertexBufferState[] _vertexBuffers;
private ulong _vertexBuffersDirty; private ulong _vertexBuffersDirty;
private bool _bindingsSet;
protected Rectangle<int> ClearScissor; protected Rectangle<int> ClearScissor;
private readonly VertexBufferUpdater _vertexBufferUpdater; private readonly VertexBufferUpdater _vertexBufferUpdater;
@@ -90,9 +89,6 @@ namespace Ryujinx.Graphics.Vulkan
private bool _tfEnabled; private bool _tfEnabled;
private bool _tfActive; private bool _tfActive;
private readonly bool _supportExtDynamic;
private readonly bool _supportExtDynamic2;
private FeedbackLoopAspects _feedbackLoop; private FeedbackLoopAspects _feedbackLoop;
private bool _passWritesDepthStencil; private bool _passWritesDepthStencil;
@@ -100,8 +96,6 @@ namespace Ryujinx.Graphics.Vulkan
public ulong DrawCount { get; private set; } public ulong DrawCount { get; private set; }
public bool RenderPassActive { get; private set; } public bool RenderPassActive { get; private set; }
private readonly int[] _vertexBufferBindings;
public unsafe PipelineBase(VulkanRenderer gd, Device device) public unsafe PipelineBase(VulkanRenderer gd, Device device)
{ {
Gd = gd; Gd = gd;
@@ -134,19 +128,7 @@ namespace Ryujinx.Graphics.Vulkan
_storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets]; _storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets];
_supportExtDynamic = gd.Capabilities.SupportsExtendedDynamicState; _newState.Initialize();
_supportExtDynamic2 = gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2;
_bindingsSet = false;
_vertexBufferBindings = new int[Constants.MaxVertexBuffers];
for (int i = 0; i < Constants.MaxVertexBuffers; i++)
{
_vertexBufferBindings[i] = i + 1;
}
_newState.Initialize(gd.Capabilities);
} }
public void Initialize() public void Initialize()
@@ -652,46 +634,19 @@ namespace Ryujinx.Graphics.Vulkan
{ {
if (texture is TextureView srcTexture) if (texture is TextureView srcTexture)
{ {
CullModeFlags oldCullMode; CullModeFlags oldCullMode = _newState.CullMode;
bool oldStencilTestEnable; bool oldStencilTestEnable = _newState.StencilTestEnable;
bool oldDepthTestEnable; bool oldDepthTestEnable = _newState.DepthTestEnable;
bool oldDepthWriteEnable; bool oldDepthWriteEnable = _newState.DepthWriteEnable;
PrimitiveTopology oldTopology;
Array16<Silk.NET.Vulkan.Viewport> oldViewports = DynamicState.Viewports; Array16<Silk.NET.Vulkan.Viewport> oldViewports = DynamicState.Viewports;
uint oldViewportsCount; uint oldViewportsCount = _newState.ViewportsCount;
PrimitiveTopology oldTopology = _topology;
if (_supportExtDynamic) _newState.CullMode = CullModeFlags.None;
{ _newState.StencilTestEnable = false;
oldCullMode = DynamicState.CullMode; _newState.DepthTestEnable = false;
oldStencilTestEnable = DynamicState.StencilTestEnable; _newState.DepthWriteEnable = false;
oldDepthTestEnable = DynamicState.DepthTestEnable; SignalStateChange();
oldDepthWriteEnable = DynamicState.DepthWriteEnable;
oldTopology = _topology;
oldViewportsCount = DynamicState.ViewportsCount;
}
else
{
oldCullMode = _newState.CullMode;
oldStencilTestEnable = _newState.StencilTestEnable;
oldDepthTestEnable = _newState.DepthTestEnable;
oldDepthWriteEnable = _newState.DepthWriteEnable;
oldTopology = _topology;
oldViewportsCount = _newState.ViewportsCount;
}
if (_supportExtDynamic)
{
DynamicState.SetCullMode(CullModeFlags.None);
DynamicState.SetDepthTestBool(false, false);
DynamicState.SetStencilTest(false);
}
else
{
_newState.CullMode = CullModeFlags.None;
_newState.StencilTestEnable = false;
_newState.DepthTestEnable = false;
_newState.DepthWriteEnable = false;
}
Gd.HelperShader.DrawTexture( Gd.HelperShader.DrawTexture(
Gd, Gd,
@@ -701,24 +656,16 @@ namespace Ryujinx.Graphics.Vulkan
srcRegion, srcRegion,
dstRegion); dstRegion);
if (_supportExtDynamic) _newState.CullMode = oldCullMode;
{ _newState.StencilTestEnable = oldStencilTestEnable;
DynamicState.SetCullMode(oldCullMode); _newState.DepthTestEnable = oldDepthTestEnable;
DynamicState.SetStencilTest(oldStencilTestEnable); _newState.DepthWriteEnable = oldDepthWriteEnable;
DynamicState.SetDepthTestBool(oldDepthTestEnable, oldDepthWriteEnable);
}
else
{
_newState.CullMode = oldCullMode;
_newState.StencilTestEnable = oldStencilTestEnable;
_newState.DepthTestEnable = oldDepthTestEnable;
_newState.DepthWriteEnable = oldDepthWriteEnable;
_newState.ViewportsCount = oldViewportsCount;
}
SetPrimitiveTopology(oldTopology); SetPrimitiveTopology(oldTopology);
DynamicState.SetViewports(ref oldViewports, oldViewportsCount); DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
_newState.ViewportsCount = oldViewportsCount;
SignalStateChange();
} }
} }
@@ -849,102 +796,48 @@ namespace Ryujinx.Graphics.Vulkan
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp) public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
{ {
bool depthBiasEnable = (enables != 0) && (factor != 0 && units != 0); DynamicState.SetDepthBias(factor, units, clamp);
bool changed = false;
if (_supportExtDynamic2) _newState.DepthBiasEnable = enables != 0;
{ SignalStateChange();
DynamicState.SetDepthBiasEnable(depthBiasEnable);
}
else if (_newState.DepthBiasEnable != depthBiasEnable)
{
_newState.DepthBiasEnable = depthBiasEnable;
changed = true;
}
if (depthBiasEnable)
{
DynamicState.SetDepthBias(factor, units, clamp);
}
if (changed)
{
SignalStateChange();
}
} }
public void SetDepthClamp(bool clamp) public void SetDepthClamp(bool clamp)
{ {
_newState.DepthClampEnable = clamp; _newState.DepthClampEnable = clamp;
SignalStateChange(); SignalStateChange();
} }
public void SetDepthMode(DepthMode mode) public void SetDepthMode(DepthMode mode)
{ {
bool newMode = mode == DepthMode.MinusOneToOne; bool oldMode = _newState.DepthMode;
_newState.DepthMode = mode == DepthMode.MinusOneToOne;
if (_newState.DepthMode == newMode) if (_newState.DepthMode != oldMode)
{ {
return; SignalStateChange();
} }
}
_newState.DepthMode = newMode; public void SetDepthTest(DepthTestDescriptor depthTest)
{
_newState.DepthTestEnable = depthTest.TestEnable;
_newState.DepthWriteEnable = depthTest.WriteEnable;
_newState.DepthCompareOp = depthTest.Func.Convert();
UpdatePassDepthStencil();
SignalStateChange(); SignalStateChange();
} }
public void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true) public void SetFaceCulling(bool enable, Face face)
{ {
if (_supportExtDynamic) _newState.CullMode = enable ? face.Convert() : CullModeFlags.None;
{ SignalStateChange();
DynamicState.SetDepthTestBool(depthTest.TestEnable, depthTest.WriteEnable);
if (depthTest.TestEnable)
{
DynamicState.SetDepthTestCompareOp(depthTest.Func.Convert());
}
}
else
{
_newState.DepthTestEnable = depthTest.TestEnable;
_newState.DepthWriteEnable = depthTest.WriteEnable;
_newState.DepthCompareOp = depthTest.Func.Convert();
if (signalChange)
{
SignalStateChange();
}
}
UpdatePassDepthStencil();
}
public void SetFaceCulling(Face face)
{
if (_supportExtDynamic)
{
DynamicState.SetCullMode(face.Convert());
}
else
{
_newState.CullMode = face.Convert();
SignalStateChange();
}
} }
public void SetFrontFace(FrontFace frontFace) public void SetFrontFace(FrontFace frontFace)
{ {
if (_supportExtDynamic) _newState.FrontFace = frontFace.Convert();
{ SignalStateChange();
DynamicState.SetFrontFace(frontFace.Convert());
}
else
{
_newState.FrontFace = frontFace.Convert();
SignalStateChange();
}
} }
public void SetImage(ShaderStage stage, int binding, ITexture image) public void SetImage(ShaderStage stage, int binding, ITexture image)
@@ -988,56 +881,28 @@ namespace Ryujinx.Graphics.Vulkan
public void SetLineParameters(float width, bool smooth) public void SetLineParameters(float width, bool smooth)
{ {
if (!Gd.IsMoltenVk) _newState.LineWidth = width;
{ SignalStateChange();
DynamicState.SetLineWidth(Gd.Capabilities.SupportsWideLines ? width : 1.0f);
}
} }
public void SetLogicOpState(bool enable, LogicalOp op) public void SetLogicOpState(bool enable, LogicalOp op)
{ {
// Vendors other than NVIDIA have a bug where it enables logical operations even for float formats,
// so we need to force disable them here.
bool logicOpEnable = enable && (Gd.Vendor == Vendor.Nvidia || _newState.Internal.LogicOpsAllowed);
_newState.LogicOpEnable = enable; _newState.LogicOpEnable = enable;
_newState.LogicOp = op.Convert();
if (Gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp)
{
if (logicOpEnable)
{
DynamicState.SetLogicOp(op.Convert());
}
}
else
{
_newState.LogicOp = op.Convert();
}
SignalStateChange(); SignalStateChange();
} }
public void SetMultisampleState(MultisampleDescriptor multisample) public void SetMultisampleState(MultisampleDescriptor multisample)
{ {
_newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable; _newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable;
_newState.AlphaToOneEnable = multisample.AlphaToOneEnable; _newState.AlphaToOneEnable = multisample.AlphaToOneEnable;
SignalStateChange(); SignalStateChange();
} }
public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel) public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
{ {
if (Gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints) _newState.PatchControlPoints = (uint)vertices;
{ SignalStateChange();
DynamicState.SetPatchControlPoints((uint)vertices);
}
else
{
_newState.PatchControlPoints = (uint)vertices;
SignalStateChange();
}
// TODO: Default levels (likely needs emulation on shaders?) // TODO: Default levels (likely needs emulation on shaders?)
} }
@@ -1054,21 +919,12 @@ namespace Ryujinx.Graphics.Vulkan
public void SetPrimitiveRestart(bool enable, int index) public void SetPrimitiveRestart(bool enable, int index)
{ {
if (_supportExtDynamic2) _newState.PrimitiveRestartEnable = enable;
{
DynamicState.SetPrimitiveRestartEnable(enable);
}
else
{
_newState.PrimitiveRestartEnable = enable;
SignalStateChange();
}
// TODO: What to do about the index? // TODO: What to do about the index?
SignalStateChange();
} }
public void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true) public void SetPrimitiveTopology(PrimitiveTopology topology)
{ {
_topology = topology; _topology = topology;
@@ -1076,18 +932,10 @@ namespace Ryujinx.Graphics.Vulkan
_newState.Topology = vkTopology; _newState.Topology = vkTopology;
if (_supportExtDynamic) SignalStateChange();
{
DynamicState.SetPrimitiveTopology(vkTopology);
}
if (signalChange)
{
SignalStateChange();
}
} }
public void SetProgram(IProgram program, bool signalChange = true) public void SetProgram(IProgram program)
{ {
ShaderCollection internalProgram = (ShaderCollection)program; ShaderCollection internalProgram = (ShaderCollection)program;
PipelineShaderStageCreateInfo[] stages = internalProgram.GetInfos(); PipelineShaderStageCreateInfo[] stages = internalProgram.GetInfos();
@@ -1103,10 +951,7 @@ namespace Ryujinx.Graphics.Vulkan
stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]); stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]);
if (signalChange) SignalStateChange();
{
SignalStateChange();
}
if (internalProgram.IsCompute) if (internalProgram.IsCompute)
{ {
@@ -1132,26 +977,18 @@ namespace Ryujinx.Graphics.Vulkan
public void SetRasterizerDiscard(bool discard) public void SetRasterizerDiscard(bool discard)
{ {
if (_supportExtDynamic2) _newState.RasterizerDiscardEnable = discard;
{ SignalStateChange();
DynamicState.SetRasterizerDiscard(discard);
}
else
{
_newState.RasterizerDiscardEnable = discard;
SignalStateChange();
}
if (!discard && Gd.IsQualcommProprietary) if (!discard && Gd.IsQualcommProprietary)
{ {
// On Adreno, enabling rasterizer discard somehow corrupts the viewport state. // On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
// Force it to be updated on next use to work around this bug. // Force it to be updated on next use to work around this bug.
DynamicState.ForceAllDirty(Gd); DynamicState.ForceAllDirty();
} }
} }
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask, bool signalChange = true) public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
{ {
int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length); int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
int writtenAttachments = 0; int writtenAttachments = 0;
@@ -1193,10 +1030,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
else else
{ {
if (signalChange) SignalStateChange();
{
SignalStateChange();
}
if (writtenAttachments != _writtenAttachmentCount) if (writtenAttachments != _writtenAttachmentCount)
{ {
@@ -1220,7 +1054,7 @@ namespace Ryujinx.Graphics.Vulkan
SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR); SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR);
} }
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions, bool signalChange = true) public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
{ {
int maxScissors = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1; int maxScissors = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
int count = Math.Min(maxScissors, regions.Length); int count = Math.Min(maxScissors, regions.Length);
@@ -1229,8 +1063,6 @@ namespace Ryujinx.Graphics.Vulkan
ClearScissor = regions[0]; ClearScissor = regions[0];
} }
DynamicState.ScissorsCount = count;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
Rectangle<int> region = regions[i]; Rectangle<int> region = regions[i];
@@ -1240,56 +1072,34 @@ namespace Ryujinx.Graphics.Vulkan
DynamicState.SetScissor(i, new Rect2D(offset, extent)); DynamicState.SetScissor(i, new Rect2D(offset, extent));
} }
if (!_supportExtDynamic) DynamicState.ScissorsCount = count;
{
_newState.ScissorsCount = (uint)count;
if (signalChange) _newState.ScissorsCount = (uint)count;
{ SignalStateChange();
SignalStateChange();
}
}
} }
public void SetStencilTest(StencilTestDescriptor stencilTest) public void SetStencilTest(StencilTestDescriptor stencilTest)
{ {
if (_supportExtDynamic) DynamicState.SetStencilMasks(
{ (uint)stencilTest.BackFuncMask,
DynamicState.SetStencilTestandOp(
stencilTest.BackSFail.Convert(),
stencilTest.BackDpPass.Convert(),
stencilTest.BackDpFail.Convert(),
stencilTest.BackFunc.Convert(),
stencilTest.FrontSFail.Convert(),
stencilTest.FrontDpPass.Convert(),
stencilTest.FrontDpFail.Convert(),
stencilTest.FrontFunc.Convert(),
stencilTest.TestEnable);
UpdatePassDepthStencil();
}
else
{
_newState.StencilBackFailOp = stencilTest.BackSFail.Convert();
_newState.StencilBackPassOp = stencilTest.BackDpPass.Convert();
_newState.StencilBackDepthFailOp = stencilTest.BackDpFail.Convert();
_newState.StencilBackCompareOp = stencilTest.BackFunc.Convert();
_newState.StencilFrontFailOp = stencilTest.FrontSFail.Convert();
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
_newState.StencilTestEnable = stencilTest.TestEnable;
UpdatePassDepthStencil();
SignalStateChange();
}
DynamicState.SetStencilMask((uint)stencilTest.BackFuncMask,
(uint)stencilTest.BackMask, (uint)stencilTest.BackMask,
(uint)stencilTest.BackFuncRef, (uint)stencilTest.BackFuncRef,
(uint)stencilTest.FrontFuncMask, (uint)stencilTest.FrontFuncMask,
(uint)stencilTest.FrontMask, (uint)stencilTest.FrontMask,
(uint)stencilTest.FrontFuncRef); (uint)stencilTest.FrontFuncRef);
_newState.StencilTestEnable = stencilTest.TestEnable;
_newState.StencilBackFailOp = stencilTest.BackSFail.Convert();
_newState.StencilBackPassOp = stencilTest.BackDpPass.Convert();
_newState.StencilBackDepthFailOp = stencilTest.BackDpFail.Convert();
_newState.StencilBackCompareOp = stencilTest.BackFunc.Convert();
_newState.StencilFrontFailOp = stencilTest.FrontSFail.Convert();
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
UpdatePassDepthStencil();
SignalStateChange();
} }
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers) public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
@@ -1410,24 +1220,12 @@ namespace Ryujinx.Graphics.Vulkan
{ {
int count = Math.Min(Constants.MaxVertexBuffers, vertexBuffers.Length); int count = Math.Min(Constants.MaxVertexBuffers, vertexBuffers.Length);
_newState.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
int validCount = 1; int validCount = 1;
if (!_bindingsSet)
{
_newState.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, _supportExtDynamic && (!Gd.IsMoltenVk || Gd.SupportsMTL31) ? null : 0, VertexInputRate.Vertex);
for (int i = 1; i < count; i++)
{
_newState.Internal.VertexBindingDescriptions[i] = new VertexInputBindingDescription((uint)i);
}
_bindingsSet = true;
}
BufferHandle lastHandle = default; BufferHandle lastHandle = default;
Auto<DisposableBuffer> lastBuffer = null; Auto<DisposableBuffer> lastBuffer = null;
bool vertexBindingDescriptionChanged = false;
bool vertexDescriptionCountChanged = false;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
@@ -1446,32 +1244,13 @@ namespace Ryujinx.Graphics.Vulkan
if (vb != null) if (vb != null)
{ {
int binding = i + 1;
int descriptorIndex = validCount++; int descriptorIndex = validCount++;
if (_supportExtDynamic && (!Gd.IsMoltenVk || Gd.SupportsMTL31)) _newState.Internal.VertexBindingDescriptions[descriptorIndex] = new VertexInputBindingDescription(
{ (uint)binding,
if (_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate != inputRate || (uint)vertexBuffer.Stride,
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding != _vertexBufferBindings[i]) inputRate);
{
_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate = inputRate;
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding = (uint)_vertexBufferBindings[i];
vertexBindingDescriptionChanged = true;
}
}
else
{
if (_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate != inputRate ||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Stride != vertexBuffer.Stride ||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding != _vertexBufferBindings[i])
{
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding = (uint)_vertexBufferBindings[i];
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Stride = (uint)vertexBuffer.Stride;
_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate = inputRate;
vertexBindingDescriptionChanged = true;
}
}
int vbSize = vertexBuffer.Buffer.Size; int vbSize = vertexBuffer.Buffer.Size;
@@ -1487,7 +1266,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
ref VertexBufferState buffer = ref _vertexBuffers[_vertexBufferBindings[i]]; ref VertexBufferState buffer = ref _vertexBuffers[binding];
int oldScalarAlign = buffer.AttributeScalarAlignment; int oldScalarAlign = buffer.AttributeScalarAlignment;
if (Gd.Capabilities.VertexBufferAlignment < 2 && if (Gd.Capabilities.VertexBufferAlignment < 2 &&
@@ -1504,7 +1283,7 @@ namespace Ryujinx.Graphics.Vulkan
vbSize, vbSize,
vertexBuffer.Stride); vertexBuffer.Stride);
buffer.BindVertexBuffer(Gd, Cbs, (uint)_vertexBufferBindings[i], ref _newState, _vertexBufferUpdater); buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState, _vertexBufferUpdater);
} }
} }
else else
@@ -1520,7 +1299,7 @@ namespace Ryujinx.Graphics.Vulkan
vbSize, vbSize,
vertexBuffer.Stride); vertexBuffer.Stride);
_vertexBuffersDirty |= 1UL << _vertexBufferBindings[i]; _vertexBuffersDirty |= 1UL << binding;
} }
buffer.AttributeScalarAlignment = oldScalarAlign; buffer.AttributeScalarAlignment = oldScalarAlign;
@@ -1530,19 +1309,11 @@ namespace Ryujinx.Graphics.Vulkan
_vertexBufferUpdater.Commit(Cbs); _vertexBufferUpdater.Commit(Cbs);
if (_newState.VertexBindingDescriptionsCount != validCount) _newState.VertexBindingDescriptionsCount = (uint)validCount;
{ SignalStateChange();
_newState.VertexBindingDescriptionsCount = (uint)validCount;
vertexDescriptionCountChanged = true;
}
if (vertexDescriptionCountChanged || vertexBindingDescriptionChanged)
{
SignalStateChange();
}
} }
public void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true) public void SetViewports(ReadOnlySpan<Viewport> viewports)
{ {
int maxViewports = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1; int maxViewports = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
int count = Math.Min(maxViewports, viewports.Length); int count = Math.Min(maxViewports, viewports.Length);
@@ -1567,15 +1338,8 @@ namespace Ryujinx.Graphics.Vulkan
Clamp(viewport.DepthFar))); Clamp(viewport.DepthFar)));
} }
if (!_supportExtDynamic) _newState.ViewportsCount = (uint)count;
{ SignalStateChange();
_newState.ViewportsCount = (uint)count;
if (signalChange)
{
SignalStateChange();
}
}
} }
public void SwapBuffer(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to) public void SwapBuffer(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
@@ -1624,7 +1388,7 @@ namespace Ryujinx.Graphics.Vulkan
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length); _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
_descriptorSetUpdater.SignalCommandBufferChange(); _descriptorSetUpdater.SignalCommandBufferChange();
DynamicState.ForceAllDirty(Gd); DynamicState.ForceAllDirty();
_currentPipelineHandle = 0; _currentPipelineHandle = 0;
} }
@@ -1782,9 +1546,8 @@ namespace Ryujinx.Graphics.Vulkan
if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop) if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
{ {
DynamicState.SetFeedbackLoop(aspects); DynamicState.SetFeedbackLoop(aspects);
_newState.FeedbackLoopDynamicState = true;
} }
else if (Gd.Capabilities.SupportsAttachmentFeedbackLoop) else
{ {
_newState.FeedbackLoopAspects = aspects; _newState.FeedbackLoopAspects = aspects;
} }
@@ -1844,14 +1607,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
// Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check. // Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
if (_supportExtDynamic) _passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
{
_passWritesDepthStencil |= (DynamicState.DepthTestEnable && DynamicState.DepthWriteEnable) || DynamicState.StencilTestEnable;
}
else
{
_passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
}
} }
private bool RecreateGraphicsPipelineIfNeeded() private bool RecreateGraphicsPipelineIfNeeded()
@@ -5,7 +5,6 @@ using System;
using VulkanFormat = Silk.NET.Vulkan.Format; using VulkanFormat = Silk.NET.Vulkan.Format;
using GALFormat = Ryujinx.Graphics.GAL.Format; using GALFormat = Ryujinx.Graphics.GAL.Format;
using PolygonMode = Silk.NET.Vulkan.PolygonMode; using PolygonMode = Silk.NET.Vulkan.PolygonMode;
using PrimitiveTopology = Ryujinx.Graphics.GAL.PrimitiveTopology;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
@@ -165,83 +164,63 @@ namespace Ryujinx.Graphics.Vulkan
public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd) public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd)
{ {
var extendedDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2;
var extendedDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
PipelineState pipeline = new(); PipelineState pipeline = new();
pipeline.Initialize(gd.Capabilities); pipeline.Initialize();
// It is assumed that Dynamic State is enabled when this conversion is used. // It is assumed that Dynamic State is enabled when this conversion is used.
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.None;
pipeline.DepthBoundsTestEnable = false; // Not implemented. pipeline.DepthBoundsTestEnable = false; // Not implemented.
pipeline.DepthClampEnable = state.DepthClampEnable; pipeline.DepthClampEnable = state.DepthClampEnable;
pipeline.AlphaToCoverageEnable = state.AlphaToCoverageEnable; pipeline.DepthTestEnable = state.DepthTest.TestEnable;
pipeline.AlphaToOneEnable = state.AlphaToOneEnable; pipeline.DepthWriteEnable = state.DepthTest.WriteEnable;
pipeline.DepthCompareOp = state.DepthTest.Func.Convert();
pipeline.DepthMode = state.DepthMode == DepthMode.MinusOneToOne; pipeline.DepthMode = state.DepthMode == DepthMode.MinusOneToOne;
pipeline.FrontFace = state.FrontFace.Convert();
pipeline.HasDepthStencil = state.DepthStencilEnable; pipeline.HasDepthStencil = state.DepthStencilEnable;
pipeline.LineWidth = state.LineWidth;
pipeline.LogicOpEnable = state.LogicOpEnable;
pipeline.LogicOp = state.LogicOp.Convert();
pipeline.PatchControlPoints = state.PatchControlPoints;
pipeline.PolygonMode = PolygonMode.Fill; // Not implemented. pipeline.PolygonMode = PolygonMode.Fill; // Not implemented.
pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
pipeline.Topology = gd.TopologyRemap(state.Topology).Convert(); pipeline.RasterizerDiscardEnable = state.RasterizerDiscard;
if (!extendedDynamicState)
{
pipeline.DepthCompareOp = state.DepthTest.Func.Convert();
pipeline.CullMode = state.CullMode.Convert();
pipeline.DepthTestEnable = state.DepthTest.TestEnable;
pipeline.DepthWriteEnable = state.DepthTest.WriteEnable;
pipeline.FrontFace = state.FrontFace.Convert();
if (gd.Capabilities.SupportsMultiView)
{
pipeline.ScissorsCount = Constants.MaxViewports;
pipeline.ViewportsCount = Constants.MaxViewports;
}
else
{
pipeline.ScissorsCount = 1;
pipeline.ViewportsCount = 1;
}
pipeline.StencilTestEnable = state.StencilTest.TestEnable;
pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert();
pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert();
pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert();
pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert();
pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
}
if (!extendedDynamicState2.ExtendedDynamicState2)
{
pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
pipeline.RasterizerDiscardEnable = state.RasterizerDiscard;
pipeline.DepthBiasEnable = (state.BiasEnable != 0) &&
(state.DepthBiasFactor != 0 && state.DepthBiasUnits != 0);
}
if (!extendedDynamicState2.ExtendedDynamicState2LogicOp)
{
pipeline.LogicOp = state.LogicOp.Convert();
}
if (!extendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
{
pipeline.PatchControlPoints = state.PatchControlPoints;
}
pipeline.SamplesCount = (uint)state.SamplesCount; pipeline.SamplesCount = (uint)state.SamplesCount;
pipeline.LogicOpEnable = state.LogicOpEnable; if (gd.Capabilities.SupportsMultiView)
{
pipeline.ScissorsCount = Constants.MaxViewports;
pipeline.ViewportsCount = Constants.MaxViewports;
}
else
{
pipeline.ScissorsCount = 1;
pipeline.ViewportsCount = 1;
}
pipeline.DepthBiasEnable = state.BiasEnable != 0;
// Stencil masks and ref are dynamic, so are 0 in the Vulkan pipeline.
pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert();
pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert();
pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert();
pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert();
pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
pipeline.StencilTestEnable = state.StencilTest.TestEnable;
pipeline.Topology = gd.TopologyRemap(state.Topology).Convert();
int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount); int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount); int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
@@ -268,7 +247,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
int descriptorIndex = 1; int descriptorIndex = 1;
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, extendedDynamicState && (!gd.IsMoltenVk || gd.SupportsMTL31) ? null : 0, VertexInputRate.Vertex); pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
Span<BufferPipelineDescriptor> vertexBuffersSpan = state.VertexBuffers.AsSpan(); Span<BufferPipelineDescriptor> vertexBuffersSpan = state.VertexBuffers.AsSpan();
Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan = pipeline.Internal.VertexBindingDescriptions.AsSpan(); Span<VertexInputBindingDescription> vertexBindingDescriptionsSpan = pipeline.Internal.VertexBindingDescriptions.AsSpan();
@@ -291,7 +270,7 @@ namespace Ryujinx.Graphics.Vulkan
// TODO: Support divisor > 1 // TODO: Support divisor > 1
vertexBindingDescriptionsSpan[descriptorIndex++] = new VertexInputBindingDescription( vertexBindingDescriptionsSpan[descriptorIndex++] = new VertexInputBindingDescription(
(uint)i + 1, (uint)i + 1,
extendedDynamicState && (!gd.IsMoltenVk || gd.SupportsMTL31) ? null : (uint)alignedStride, (uint)alignedStride,
inputRate); inputRate);
} }
} }
@@ -2,7 +2,6 @@ using Ryujinx.Common.Memory;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT; using Silk.NET.Vulkan.Extensions.EXT;
using System; using System;
using System.Numerics;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
@@ -11,7 +10,6 @@ namespace Ryujinx.Graphics.Vulkan
private float _depthBiasSlopeFactor; private float _depthBiasSlopeFactor;
private float _depthBiasConstantFactor; private float _depthBiasConstantFactor;
private float _depthBiasClamp; private float _depthBiasClamp;
private bool _depthBiasEnable;
public int ScissorsCount; public int ScissorsCount;
private Array16<Rect2D> _scissors; private Array16<Rect2D> _scissors;
@@ -23,23 +21,6 @@ namespace Ryujinx.Graphics.Vulkan
private uint _frontWriteMask; private uint _frontWriteMask;
private uint _frontReference; private uint _frontReference;
private StencilOp _backFailOp;
private StencilOp _backPassOp;
private StencilOp _backDepthFailOp;
private CompareOp _backCompareOp;
private StencilOp _frontFailOp;
private StencilOp _frontPassOp;
private StencilOp _frontDepthFailOp;
private CompareOp _frontCompareOp;
private float _lineWidth;
public bool StencilTestEnable;
public bool DepthTestEnable;
public bool DepthWriteEnable;
private CompareOp _depthCompareOp;
private Array4<float> _blendConstants; private Array4<float> _blendConstants;
private FeedbackLoopAspects _feedbackLoopAspects; private FeedbackLoopAspects _feedbackLoopAspects;
@@ -47,19 +28,6 @@ namespace Ryujinx.Graphics.Vulkan
public uint ViewportsCount; public uint ViewportsCount;
public Array16<Viewport> Viewports; public Array16<Viewport> Viewports;
public CullModeFlags CullMode;
private FrontFace _frontFace;
private bool _discard;
private LogicOp _logicOp;
private uint _patchControlPoints;
public PrimitiveTopology Topology;
private bool _primitiveRestartEnable;
[Flags] [Flags]
private enum DirtyFlags private enum DirtyFlags
{ {
@@ -70,21 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
Stencil = 1 << 3, Stencil = 1 << 3,
Viewport = 1 << 4, Viewport = 1 << 4,
FeedbackLoop = 1 << 5, FeedbackLoop = 1 << 5,
CullMode = 1 << 6, All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
FrontFace = 1 << 7,
DepthTestBool = 1 << 8,
DepthTestCompareOp = 1 << 9,
StencilTestEnableAndStencilOp = 1 << 10,
LineWidth = 1 << 11,
RasterDiscard = 1 << 12,
LogicOp = 1 << 13,
PatchControlPoints = 1 << 14,
PrimitiveRestart = 1 << 15,
PrimitiveTopology = 1 << 16,
DepthBiasEnable = 1 << 17,
Standard = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
Extended = CullMode | FrontFace | DepthTestBool | DepthTestCompareOp | StencilTestEnableAndStencilOp | PrimitiveTopology,
Extended2 = RasterDiscard | PrimitiveRestart | DepthBiasEnable,
} }
private DirtyFlags _dirty; private DirtyFlags _dirty;
@@ -95,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
_blendConstants[1] = g; _blendConstants[1] = g;
_blendConstants[2] = b; _blendConstants[2] = b;
_blendConstants[3] = a; _blendConstants[3] = a;
_dirty |= DirtyFlags.Blend; _dirty |= DirtyFlags.Blend;
} }
@@ -107,64 +62,15 @@ namespace Ryujinx.Graphics.Vulkan
_dirty |= DirtyFlags.DepthBias; _dirty |= DirtyFlags.DepthBias;
} }
public void SetDepthBiasEnable(bool enable)
{
_depthBiasEnable = enable;
_dirty |= DirtyFlags.DepthBiasEnable;
}
public void SetScissor(int index, Rect2D scissor) public void SetScissor(int index, Rect2D scissor)
{ {
_scissors[index] = scissor; _scissors[index] = scissor;
_dirty |= DirtyFlags.Scissor; _dirty |= DirtyFlags.Scissor;
} }
public void SetDepthTestBool(bool testEnable, bool writeEnable) public void SetStencilMasks(
{ uint backCompareMask,
DepthTestEnable = testEnable;
DepthWriteEnable = writeEnable;
_dirty |= DirtyFlags.DepthTestBool;
}
public void SetDepthTestCompareOp(CompareOp depthTestOp)
{
_depthCompareOp = depthTestOp;
_dirty |= DirtyFlags.DepthTestCompareOp;
}
public void SetStencilTestandOp(
StencilOp backFailOp,
StencilOp backPassOp,
StencilOp backDepthFailOp,
CompareOp backCompareOp,
StencilOp frontFailOp,
StencilOp frontPassOp,
StencilOp frontDepthFailOp,
CompareOp frontCompareOp,
bool stencilTestEnable)
{
_backFailOp = backFailOp;
_backPassOp = backPassOp;
_backDepthFailOp = backDepthFailOp;
_backCompareOp = backCompareOp;
_frontFailOp = frontFailOp;
_frontPassOp = frontPassOp;
_frontDepthFailOp = frontDepthFailOp;
_frontCompareOp = frontCompareOp;
StencilTestEnable = stencilTestEnable;
_dirty |= DirtyFlags.StencilTestEnableAndStencilOp;
}
public void SetStencilTest(bool stencilTestEnable)
{
StencilTestEnable = stencilTestEnable;
_dirty |= DirtyFlags.StencilTestEnableAndStencilOp;
}
public void SetStencilMask(uint backCompareMask,
uint backWriteMask, uint backWriteMask,
uint backReference, uint backReference,
uint frontCompareMask, uint frontCompareMask,
@@ -177,46 +83,28 @@ namespace Ryujinx.Graphics.Vulkan
_frontCompareMask = frontCompareMask; _frontCompareMask = frontCompareMask;
_frontWriteMask = frontWriteMask; _frontWriteMask = frontWriteMask;
_frontReference = frontReference; _frontReference = frontReference;
_dirty |= DirtyFlags.Stencil; _dirty |= DirtyFlags.Stencil;
} }
public void SetViewport(int index, Viewport viewport) public void SetViewport(int index, Viewport viewport)
{ {
Viewports[index] = viewport; Viewports[index] = viewport;
_dirty |= DirtyFlags.Viewport; _dirty |= DirtyFlags.Viewport;
} }
public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount) public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
{ {
if (!Viewports.Equals(viewports) || ViewportsCount != viewportsCount) Viewports = viewports;
ViewportsCount = viewportsCount;
if (ViewportsCount != 0)
{ {
Viewports = viewports; _dirty |= DirtyFlags.Viewport;
ViewportsCount = viewportsCount;
if (ViewportsCount != 0)
{
_dirty |= DirtyFlags.Viewport;
}
} }
} }
public void SetCullMode(CullModeFlags cullMode)
{
CullMode = cullMode;
_dirty |= DirtyFlags.CullMode;
}
public void SetFrontFace(FrontFace frontFace)
{
_frontFace = frontFace;
_dirty |= DirtyFlags.FrontFace;
}
public void SetLineWidth(float width)
{
_lineWidth = width;
_dirty |= DirtyFlags.LineWidth;
}
public void SetFeedbackLoop(FeedbackLoopAspects aspects) public void SetFeedbackLoop(FeedbackLoopAspects aspects)
{ {
_feedbackLoopAspects = aspects; _feedbackLoopAspects = aspects;
@@ -224,149 +112,43 @@ namespace Ryujinx.Graphics.Vulkan
_dirty |= DirtyFlags.FeedbackLoop; _dirty |= DirtyFlags.FeedbackLoop;
} }
public void SetRasterizerDiscard(bool discard) public void ForceAllDirty()
{ {
_discard = discard; _dirty = DirtyFlags.All;
_dirty |= DirtyFlags.RasterDiscard;
}
public void SetPrimitiveRestartEnable(bool primitiveRestart)
{
_primitiveRestartEnable = primitiveRestart;
_dirty |= DirtyFlags.PrimitiveRestart;
}
public void SetPrimitiveTopology(PrimitiveTopology primitiveTopology)
{
Topology = primitiveTopology;
_dirty |= DirtyFlags.PrimitiveTopology;
}
public void SetLogicOp(LogicOp op)
{
_logicOp = op;
_dirty |= DirtyFlags.LogicOp;
}
public void SetPatchControlPoints(uint points)
{
_patchControlPoints = points;
_dirty |= DirtyFlags.PatchControlPoints;
}
public void ForceAllDirty(VulkanRenderer gd)
{
_dirty = DirtyFlags.Standard;
if (gd.Capabilities.SupportsExtendedDynamicState)
{
_dirty |= DirtyFlags.Extended;
}
if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2)
{
_dirty |= DirtyFlags.Extended2;
if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp)
{
_dirty |= DirtyFlags.LogicOp;
}
if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
{
_dirty |= DirtyFlags.PatchControlPoints;
}
}
if (!gd.IsMoltenVk)
{
_dirty |= DirtyFlags.LineWidth;
}
if (gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
{
_dirty |= DirtyFlags.FeedbackLoop;
}
} }
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer) public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
{ {
if (_dirty == DirtyFlags.None) Vk api = gd.Api;
if (_dirty.HasFlag(DirtyFlags.Blend))
{ {
return; RecordBlend(api, commandBuffer);
} }
var api = gd.Api; if (_dirty.HasFlag(DirtyFlags.DepthBias))
var extendedStateApi = gd.ExtendedDynamicStateApi;
var extendedState2Api = gd.ExtendedDynamicState2Api;
var dynamicFeedbackLoopApi = gd.DynamicFeedbackLoopApi;
DirtyFlags dirtyFlags = _dirty;
while (dirtyFlags != DirtyFlags.None)
{ {
int bitIndex = BitOperations.TrailingZeroCount((uint)dirtyFlags); RecordDepthBias(api, commandBuffer);
DirtyFlags currentFlag = (DirtyFlags)(1 << bitIndex); }
switch (currentFlag) if (_dirty.HasFlag(DirtyFlags.Scissor))
{ {
case DirtyFlags.Blend: RecordScissor(api, commandBuffer);
RecordBlend(api, commandBuffer); }
break;
case DirtyFlags.DepthBias:
RecordDepthBias(api, commandBuffer);
break;
case DirtyFlags.Scissor:
RecordScissor(gd, commandBuffer);
break;
case DirtyFlags.Stencil:
RecordStencil(api, commandBuffer);
break;
case DirtyFlags.Viewport:
RecordViewport(gd, commandBuffer);
break;
case DirtyFlags.FeedbackLoop:
RecordFeedbackLoop(dynamicFeedbackLoopApi, commandBuffer);
break;
case DirtyFlags.CullMode:
RecordCullMode(extendedStateApi, commandBuffer);
break;
case DirtyFlags.FrontFace:
RecordFrontFace(extendedStateApi, commandBuffer);
break;
case DirtyFlags.DepthTestBool:
RecordDepthTestBool(extendedStateApi, commandBuffer);
break;
case DirtyFlags.DepthTestCompareOp:
RecordDepthTestCompareOp(extendedStateApi, commandBuffer);
break;
case DirtyFlags.StencilTestEnableAndStencilOp:
RecordStencilTestAndOp(extendedStateApi, commandBuffer);
break;
case DirtyFlags.LineWidth:
RecordLineWidth(api, commandBuffer);
break;
case DirtyFlags.RasterDiscard:
RecordRasterizationDiscard(extendedState2Api, commandBuffer);
break;
case DirtyFlags.LogicOp:
RecordLogicOp(extendedState2Api, commandBuffer);
break;
case DirtyFlags.PatchControlPoints:
RecordPatchControlPoints(extendedState2Api, commandBuffer);
break;
case DirtyFlags.PrimitiveRestart:
RecordPrimitiveRestartEnable(gd, commandBuffer);
break;
case DirtyFlags.PrimitiveTopology:
RecordPrimitiveTopology(extendedStateApi, commandBuffer);
break;
case DirtyFlags.DepthBiasEnable:
RecordDepthBiasEnable(extendedState2Api, commandBuffer);
break;
}
dirtyFlags &= ~currentFlag; if (_dirty.HasFlag(DirtyFlags.Stencil))
{
RecordStencilMasks(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.Viewport))
{
RecordViewport(api, commandBuffer);
}
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
{
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
} }
_dirty = DirtyFlags.None; _dirty = DirtyFlags.None;
@@ -382,27 +164,15 @@ namespace Ryujinx.Graphics.Vulkan
api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor); api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);
} }
private readonly void RecordDepthBiasEnable(ExtExtendedDynamicState2 gd, CommandBuffer commandBuffer) private void RecordScissor(Vk api, CommandBuffer commandBuffer)
{
gd.CmdSetDepthBiasEnable(commandBuffer, _depthBiasEnable);
}
private void RecordScissor(VulkanRenderer gd, CommandBuffer commandBuffer)
{ {
if (ScissorsCount != 0) if (ScissorsCount != 0)
{ {
if (gd.Capabilities.SupportsExtendedDynamicState) api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
{
gd.ExtendedDynamicStateApi.CmdSetScissorWithCount(commandBuffer, (uint)ScissorsCount, _scissors.AsSpan());
}
else
{
gd.Api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
}
} }
} }
private readonly void RecordStencil(Vk api, CommandBuffer commandBuffer) private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
{ {
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask); api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask); api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
@@ -412,107 +182,12 @@ namespace Ryujinx.Graphics.Vulkan
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference); api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
} }
private readonly void RecordStencilTestAndOp(ExtExtendedDynamicState api, CommandBuffer commandBuffer) private void RecordViewport(Vk api, CommandBuffer commandBuffer)
{ {
api.CmdSetStencilTestEnable(commandBuffer, StencilTestEnable); if (ViewportsCount != 0)
api.CmdSetStencilOp(commandBuffer, StencilFaceFlags.FaceBackBit, _backFailOp, _backPassOp, _backDepthFailOp, _backCompareOp);
api.CmdSetStencilOp(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontFailOp, _frontPassOp, _frontDepthFailOp, _frontCompareOp);
}
private void RecordViewport(VulkanRenderer gd, CommandBuffer commandBuffer)
{
if (ViewportsCount == 0)
{ {
return; api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
} }
if (gd.Capabilities.SupportsExtendedDynamicState)
{
gd.ExtendedDynamicStateApi.CmdSetViewportWithCount(commandBuffer, ViewportsCount, Viewports.AsSpan());
}
else
{
gd.Api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
}
}
private readonly void RecordCullMode(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
{
api.CmdSetCullMode(commandBuffer, CullMode);
}
private readonly void RecordFrontFace(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
{
api.CmdSetFrontFace(commandBuffer, _frontFace);
}
private readonly void RecordDepthTestBool(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
{
api.CmdSetDepthTestEnable(commandBuffer, DepthTestEnable);
api.CmdSetDepthWriteEnable(commandBuffer, DepthWriteEnable);
}
private readonly void RecordDepthTestCompareOp(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
{
api.CmdSetDepthCompareOp(commandBuffer, _depthCompareOp);
}
private readonly void RecordRasterizationDiscard(ExtExtendedDynamicState2 extendedDynamicState2Api, CommandBuffer commandBuffer)
{
extendedDynamicState2Api.CmdSetRasterizerDiscardEnable(commandBuffer, _discard);
}
private readonly void RecordPrimitiveRestartEnable(VulkanRenderer gd, CommandBuffer commandBuffer)
{
bool primitiveRestartEnable = _primitiveRestartEnable;
bool topologySupportsRestart;
if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
{
topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart ||
Topology != PrimitiveTopology.PatchList;
}
else
{
topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
Topology == PrimitiveTopology.TriangleStrip ||
Topology == PrimitiveTopology.TriangleFan ||
Topology == PrimitiveTopology.LineStripWithAdjacency ||
Topology == PrimitiveTopology.TriangleStripWithAdjacency;
}
primitiveRestartEnable &= topologySupportsRestart;
// Cannot disable primitiveRestartEnable for these Topologies on MacOS.
if (gd.IsMoltenVk)
{
primitiveRestartEnable = true;
}
gd.ExtendedDynamicState2Api.CmdSetPrimitiveRestartEnable(commandBuffer, primitiveRestartEnable);
}
private readonly void RecordPrimitiveTopology(ExtExtendedDynamicState extendedDynamicStateApi, CommandBuffer commandBuffer)
{
extendedDynamicStateApi.CmdSetPrimitiveTopology(commandBuffer, Topology);
}
private readonly void RecordLogicOp(ExtExtendedDynamicState2 extendedDynamicState2Api, CommandBuffer commandBuffer)
{
extendedDynamicState2Api.CmdSetLogicOp(commandBuffer, _logicOp);
}
private readonly void RecordPatchControlPoints(ExtExtendedDynamicState2 extendedDynamicState2Api, CommandBuffer commandBuffer)
{
extendedDynamicState2Api.CmdSetPatchControlPoints(commandBuffer, _patchControlPoints);
}
private readonly void RecordLineWidth(Vk api, CommandBuffer commandBuffer)
{
api.CmdSetLineWidth(commandBuffer, _lineWidth);
} }
private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer) private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
@@ -8,15 +8,11 @@ namespace Ryujinx.Graphics.Vulkan
{ {
} }
public void SetRenderTarget(TextureView view, uint width, uint height, bool signalChange = true) public void SetRenderTarget(TextureView view, uint width, uint height)
{ {
CreateFramebuffer(view, width, height); CreateFramebuffer(view, width, height);
CreateRenderPass(); CreateRenderPass();
SignalStateChange();
if (signalChange)
{
SignalStateChange();
}
} }
private void CreateFramebuffer(TextureView view, uint width, uint height) private void CreateFramebuffer(TextureView view, uint width, uint height)
+350 -452
View File
@@ -7,258 +7,312 @@ namespace Ryujinx.Graphics.Vulkan
{ {
struct PipelineState : IDisposable struct PipelineState : IDisposable
{ {
private const int MaxDynamicStatesCount = 23; private const int MaxDynamicStatesCount = 9;
public PipelineUid Internal; public PipelineUid Internal;
public PolygonMode PolygonMode public float LineWidth
{ {
readonly get => (PolygonMode)((Internal.Id0 >> 0) & 0x3FFFFFFF); readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 0) & 0xFFFFFFFF));
set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFFC0000000) | ((ulong)value << 0); set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
} }
public uint StagesCount public float DepthBiasClamp
{ {
readonly get => (byte)((Internal.Id0 >> 30) & 0xFF); readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 32) & 0xFFFFFFFF));
set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30); set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
} }
public uint VertexAttributeDescriptionsCount public float DepthBiasConstantFactor
{ {
readonly get => (byte)((Internal.Id0 >> 38) & 0xFF); readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 0) & 0xFFFFFFFF));
set => Internal.Id0 = (Internal.Id0 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38); set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
} }
public uint VertexBindingDescriptionsCount public float DepthBiasSlopeFactor
{ {
readonly get => (byte)((Internal.Id0 >> 46) & 0xFF); readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 32) & 0xFFFFFFFF));
set => Internal.Id0 = (Internal.Id0 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46); set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
} }
public uint ViewportsCount public uint StencilFrontCompareMask
{
readonly get => (byte)((Internal.Id0 >> 54) & 0xFF);
set => Internal.Id0 = (Internal.Id0 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
}
public uint ScissorsCount
{
readonly get => (byte)((Internal.Id1 >> 0) & 0xFF);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
}
public uint ColorBlendAttachmentStateCount
{
readonly get => (byte)((Internal.Id1 >> 8) & 0xFF);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
}
public PrimitiveTopology Topology
{
readonly get => (PrimitiveTopology)((Internal.Id1 >> 16) & 0xF);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
}
public LogicOp LogicOp
{
readonly get => (LogicOp)((Internal.Id1 >> 20) & 0xF);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
}
public CompareOp DepthCompareOp
{
readonly get => (CompareOp)((Internal.Id1 >> 24) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
}
public StencilOp StencilFrontFailOp
{
readonly get => (StencilOp)((Internal.Id1 >> 27) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
}
public StencilOp StencilFrontPassOp
{
readonly get => (StencilOp)((Internal.Id1 >> 30) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
}
public StencilOp StencilFrontDepthFailOp
{
readonly get => (StencilOp)((Internal.Id1 >> 33) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
}
public CompareOp StencilFrontCompareOp
{
readonly get => (CompareOp)((Internal.Id1 >> 36) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
}
public StencilOp StencilBackFailOp
{
readonly get => (StencilOp)((Internal.Id1 >> 39) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
}
public StencilOp StencilBackPassOp
{
readonly get => (StencilOp)((Internal.Id1 >> 42) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
}
public StencilOp StencilBackDepthFailOp
{
readonly get => (StencilOp)((Internal.Id1 >> 45) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
}
public CompareOp StencilBackCompareOp
{
readonly get => (CompareOp)((Internal.Id1 >> 48) & 0x7);
set => Internal.Id1 = (Internal.Id1 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
}
public CullModeFlags CullMode
{
readonly get => (CullModeFlags)((Internal.Id1 >> 51) & 0x3);
set => Internal.Id1 = (Internal.Id1 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
}
public bool PrimitiveRestartEnable
{
readonly get => ((Internal.Id1 >> 53) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
}
public bool DepthClampEnable
{
readonly get => ((Internal.Id1 >> 54) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
}
public bool RasterizerDiscardEnable
{
readonly get => ((Internal.Id1 >> 55) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
}
public FrontFace FrontFace
{
readonly get => (FrontFace)((Internal.Id1 >> 56) & 0x1);
set => Internal.Id1 = (Internal.Id1 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
}
public bool DepthBiasEnable
{
readonly get => ((Internal.Id1 >> 57) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
}
public bool DepthTestEnable
{
readonly get => ((Internal.Id1 >> 58) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
}
public bool DepthWriteEnable
{
readonly get => ((Internal.Id1 >> 59) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
}
public bool DepthBoundsTestEnable
{
readonly get => ((Internal.Id1 >> 60) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
}
public bool StencilTestEnable
{
readonly get => ((Internal.Id1 >> 61) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
}
public bool LogicOpEnable
{
readonly get => ((Internal.Id1 >> 62) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
}
public bool HasDepthStencil
{
readonly get => ((Internal.Id1 >> 63) & 0x1) != 0UL;
set => Internal.Id1 = (Internal.Id1 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
}
public uint PatchControlPoints
{ {
readonly get => (uint)((Internal.Id2 >> 0) & 0xFFFFFFFF); readonly get => (uint)((Internal.Id2 >> 0) & 0xFFFFFFFF);
set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF00000000) | ((ulong)value << 0); set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
} }
public uint SamplesCount public uint StencilFrontWriteMask
{ {
readonly get => (uint)((Internal.Id2 >> 32) & 0xFFFFFFFF); readonly get => (uint)((Internal.Id2 >> 32) & 0xFFFFFFFF);
set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF) | ((ulong)value << 32); set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF) | ((ulong)value << 32);
} }
public uint StencilFrontReference
{
readonly get => (uint)((Internal.Id3 >> 0) & 0xFFFFFFFF);
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
}
public uint StencilBackCompareMask
{
readonly get => (uint)((Internal.Id3 >> 32) & 0xFFFFFFFF);
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF) | ((ulong)value << 32);
}
public uint StencilBackWriteMask
{
readonly get => (uint)((Internal.Id4 >> 0) & 0xFFFFFFFF);
set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
}
public uint StencilBackReference
{
readonly get => (uint)((Internal.Id4 >> 32) & 0xFFFFFFFF);
set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32);
}
public PolygonMode PolygonMode
{
readonly get => (PolygonMode)((Internal.Id5 >> 0) & 0x3FFFFFFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
}
public uint StagesCount
{
readonly get => (byte)((Internal.Id5 >> 30) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
}
public uint VertexAttributeDescriptionsCount
{
readonly get => (byte)((Internal.Id5 >> 38) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
}
public uint VertexBindingDescriptionsCount
{
readonly get => (byte)((Internal.Id5 >> 46) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
}
public uint ViewportsCount
{
readonly get => (byte)((Internal.Id5 >> 54) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
}
public uint ScissorsCount
{
readonly get => (byte)((Internal.Id6 >> 0) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
}
public uint ColorBlendAttachmentStateCount
{
readonly get => (byte)((Internal.Id6 >> 8) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
}
public PrimitiveTopology Topology
{
readonly get => (PrimitiveTopology)((Internal.Id6 >> 16) & 0xF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
}
public LogicOp LogicOp
{
readonly get => (LogicOp)((Internal.Id6 >> 20) & 0xF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
}
public CompareOp DepthCompareOp
{
readonly get => (CompareOp)((Internal.Id6 >> 24) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
}
public StencilOp StencilFrontFailOp
{
readonly get => (StencilOp)((Internal.Id6 >> 27) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
}
public StencilOp StencilFrontPassOp
{
readonly get => (StencilOp)((Internal.Id6 >> 30) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
}
public StencilOp StencilFrontDepthFailOp
{
readonly get => (StencilOp)((Internal.Id6 >> 33) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
}
public CompareOp StencilFrontCompareOp
{
readonly get => (CompareOp)((Internal.Id6 >> 36) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
}
public StencilOp StencilBackFailOp
{
readonly get => (StencilOp)((Internal.Id6 >> 39) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
}
public StencilOp StencilBackPassOp
{
readonly get => (StencilOp)((Internal.Id6 >> 42) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
}
public StencilOp StencilBackDepthFailOp
{
readonly get => (StencilOp)((Internal.Id6 >> 45) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
}
public CompareOp StencilBackCompareOp
{
readonly get => (CompareOp)((Internal.Id6 >> 48) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
}
public CullModeFlags CullMode
{
readonly get => (CullModeFlags)((Internal.Id6 >> 51) & 0x3);
set => Internal.Id6 = (Internal.Id6 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
}
public bool PrimitiveRestartEnable
{
readonly get => ((Internal.Id6 >> 53) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
}
public bool DepthClampEnable
{
readonly get => ((Internal.Id6 >> 54) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
}
public bool RasterizerDiscardEnable
{
readonly get => ((Internal.Id6 >> 55) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
}
public FrontFace FrontFace
{
readonly get => (FrontFace)((Internal.Id6 >> 56) & 0x1);
set => Internal.Id6 = (Internal.Id6 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
}
public bool DepthBiasEnable
{
readonly get => ((Internal.Id6 >> 57) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
}
public bool DepthTestEnable
{
readonly get => ((Internal.Id6 >> 58) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
}
public bool DepthWriteEnable
{
readonly get => ((Internal.Id6 >> 59) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
}
public bool DepthBoundsTestEnable
{
readonly get => ((Internal.Id6 >> 60) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
}
public bool StencilTestEnable
{
readonly get => ((Internal.Id6 >> 61) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
}
public bool LogicOpEnable
{
readonly get => ((Internal.Id6 >> 62) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
}
public bool HasDepthStencil
{
readonly get => ((Internal.Id6 >> 63) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
}
public uint PatchControlPoints
{
readonly get => (uint)((Internal.Id7 >> 0) & 0xFFFFFFFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
}
public uint SamplesCount
{
readonly get => (uint)((Internal.Id7 >> 32) & 0xFFFFFFFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF) | ((ulong)value << 32);
}
public bool AlphaToCoverageEnable public bool AlphaToCoverageEnable
{ {
readonly get => ((Internal.Id3 >> 0) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 0) & 0x1) != 0UL;
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
} }
public bool AlphaToOneEnable public bool AlphaToOneEnable
{ {
readonly get => ((Internal.Id3 >> 1) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 1) & 0x1) != 0UL;
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
} }
public bool AdvancedBlendSrcPreMultiplied public bool AdvancedBlendSrcPreMultiplied
{ {
readonly get => ((Internal.Id3 >> 2) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 2) & 0x1) != 0UL;
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
} }
public bool AdvancedBlendDstPreMultiplied public bool AdvancedBlendDstPreMultiplied
{ {
readonly get => ((Internal.Id3 >> 3) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 3) & 0x1) != 0UL;
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
} }
public BlendOverlapEXT AdvancedBlendOverlap public BlendOverlapEXT AdvancedBlendOverlap
{ {
readonly get => (BlendOverlapEXT)((Internal.Id3 >> 4) & 0x3); readonly get => (BlendOverlapEXT)((Internal.Id8 >> 4) & 0x3);
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
} }
public bool DepthMode public bool DepthMode
{ {
readonly get => ((Internal.Id3 >> 6) & 0x1) != 0UL; readonly get => ((Internal.Id8 >> 6) & 0x1) != 0UL;
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
} }
public FeedbackLoopAspects FeedbackLoopAspects public FeedbackLoopAspects FeedbackLoopAspects
{ {
readonly get => (FeedbackLoopAspects)((Internal.Id3 >> 7) & 0x3); readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3);
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7); set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7);
} }
public bool HasTessellationControlShader; public bool HasTessellationControlShader;
public bool FeedbackLoopDynamicState;
public NativeArray<PipelineShaderStageCreateInfo> Stages; public NativeArray<PipelineShaderStageCreateInfo> Stages;
public PipelineLayout PipelineLayout; public PipelineLayout PipelineLayout;
public SpecData SpecializationData; public SpecData SpecializationData;
private Array32<VertexInputAttributeDescription> _vertexAttributeDescriptions2; private Array32<VertexInputAttributeDescription> _vertexAttributeDescriptions2;
private bool _supportsExtDynamicState; public void Initialize()
private PhysicalDeviceExtendedDynamicState2FeaturesEXT _supportsExtDynamicState2;
private bool _supportsFeedBackLoopDynamicState;
private uint _blendEnables;
public void Initialize(HardwareCapabilities capabilities)
{ {
HasTessellationControlShader = false; HasTessellationControlShader = false;
Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages); Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
@@ -267,54 +321,9 @@ namespace Ryujinx.Graphics.Vulkan
AdvancedBlendDstPreMultiplied = true; AdvancedBlendDstPreMultiplied = true;
AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt; AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
LineWidth = 1f;
SamplesCount = 1;
DepthMode = true; DepthMode = true;
PolygonMode = PolygonMode.Fill;
DepthBoundsTestEnable = false;
_supportsExtDynamicState = capabilities.SupportsExtendedDynamicState;
_supportsExtDynamicState2 = capabilities.SupportsExtendedDynamicState2;
_supportsFeedBackLoopDynamicState = capabilities.SupportsDynamicAttachmentFeedbackLoop;
if (_supportsExtDynamicState)
{
StencilFrontFailOp = 0;
StencilFrontPassOp = 0;
StencilFrontDepthFailOp = 0;
StencilFrontCompareOp = 0;
StencilBackFailOp = 0;
StencilBackPassOp = 0;
StencilBackDepthFailOp = 0;
StencilBackCompareOp = 0;
ViewportsCount = 0;
ScissorsCount = 0;
CullMode = 0;
FrontFace = 0;
DepthTestEnable = false;
DepthWriteEnable = false;
DepthCompareOp = 0;
StencilTestEnable = false;
}
if (_supportsExtDynamicState2.ExtendedDynamicState2)
{
PrimitiveRestartEnable = false;
DepthBiasEnable = false;
RasterizerDiscardEnable = false;
if (_supportsExtDynamicState2.ExtendedDynamicState2LogicOp)
{
LogicOp = 0;
}
if (_supportsExtDynamicState2.ExtendedDynamicState2PatchControlPoints)
{
PatchControlPoints = 0;
}
}
} }
public unsafe Auto<DisposablePipeline> CreateComputePipeline( public unsafe Auto<DisposablePipeline> CreateComputePipeline(
@@ -332,6 +341,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
SType = StructureType.ComputePipelineCreateInfo, SType = StructureType.ComputePipelineCreateInfo,
Stage = Stages[0], Stage = Stages[0],
BasePipelineIndex = -1,
Layout = PipelineLayout, Layout = PipelineLayout,
}; };
@@ -367,74 +377,6 @@ namespace Ryujinx.Graphics.Vulkan
return pipeline; return pipeline;
} }
private void CheckCapability(VulkanRenderer gd)
{
// Vendors other than NVIDIA have a bug where it enables logical operations even for float formats,
// so we need to force disable them here.
LogicOpEnable = LogicOpEnable && (gd.Vendor == Vendor.Nvidia || Internal.LogicOpsAllowed);
if (!_supportsExtDynamicState)
{
DepthWriteEnable = DepthWriteEnable && DepthTestEnable;
DepthCompareOp = DepthTestEnable ? DepthCompareOp : default;
}
if (!_supportsExtDynamicState2.ExtendedDynamicState2LogicOp)
{
LogicOp = LogicOpEnable ? LogicOp : default;
}
if (!_supportsExtDynamicState2.ExtendedDynamicState2)
{
bool topologySupportsRestart;
if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
{
topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart ||
Topology != PrimitiveTopology.PatchList;
}
else
{
topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
Topology == PrimitiveTopology.TriangleStrip ||
Topology == PrimitiveTopology.TriangleFan ||
Topology == PrimitiveTopology.LineStripWithAdjacency ||
Topology == PrimitiveTopology.TriangleStripWithAdjacency;
}
PrimitiveRestartEnable &= topologySupportsRestart;
}
if (_supportsExtDynamicState)
{
Topology = Topology.ConvertToClass();
}
Topology = HasTessellationControlShader ? PrimitiveTopology.PatchList : Topology;
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
{
_blendEnables = 0;
// Blend can't be enabled for integer formats, so let's make sure it is disabled.
uint attachmentIntegerFormatMask = Internal.AttachmentIntegerFormatMask;
while (attachmentIntegerFormatMask != 0)
{
int i = BitOperations.TrailingZeroCount(attachmentIntegerFormatMask);
if (Internal.ColorBlendAttachmentState[i].BlendEnable)
{
_blendEnables |= 1u << i;
}
Internal.ColorBlendAttachmentState[i].BlendEnable = false;
attachmentIntegerFormatMask &= ~(1u << i);
}
}
}
public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline( public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline(
VulkanRenderer gd, VulkanRenderer gd,
Device device, Device device,
@@ -443,17 +385,6 @@ namespace Ryujinx.Graphics.Vulkan
RenderPass renderPass, RenderPass renderPass,
bool throwOnError = false) bool throwOnError = false)
{ {
CheckCapability(gd);
// Using patches topology without a tessellation shader is invalid.
// If we find such a case, return null pipeline to skip the draw.
if (Topology == PrimitiveTopology.PatchList && !HasTessellationControlShader)
{
program.AddGraphicsPipeline(ref Internal, null);
return null;
}
if (program.TryGetGraphicsPipeline(ref Internal, out Auto<DisposablePipeline> pipeline)) if (program.TryGetGraphicsPipeline(ref Internal, out Auto<DisposablePipeline> pipeline))
{ {
return pipeline; return pipeline;
@@ -463,7 +394,7 @@ namespace Ryujinx.Graphics.Vulkan
bool isMoltenVk = gd.IsMoltenVk; bool isMoltenVk = gd.IsMoltenVk;
if (isMoltenVk && !_supportsExtDynamicState) if (isMoltenVk)
{ {
UpdateVertexAttributeDescriptions(gd); UpdateVertexAttributeDescriptions(gd);
} }
@@ -477,7 +408,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
SType = StructureType.PipelineVertexInputStateCreateInfo, SType = StructureType.PipelineVertexInputStateCreateInfo,
VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount, VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
PVertexAttributeDescriptions = isMoltenVk && !_supportsExtDynamicState ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions, PVertexAttributeDescriptions = isMoltenVk ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
VertexBindingDescriptionCount = VertexBindingDescriptionsCount, VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
PVertexBindingDescriptions = pVertexBindingDescriptions, PVertexBindingDescriptions = pVertexBindingDescriptions,
}; };
@@ -513,22 +444,33 @@ namespace Ryujinx.Graphics.Vulkan
PipelineInputAssemblyStateCreateInfo inputAssemblyState = new() PipelineInputAssemblyStateCreateInfo inputAssemblyState = new()
{ {
SType = StructureType.PipelineInputAssemblyStateCreateInfo, SType = StructureType.PipelineInputAssemblyStateCreateInfo,
Topology = Topology, PrimitiveRestartEnable = primitiveRestartEnable,
Topology = HasTessellationControlShader ? PrimitiveTopology.PatchList : Topology,
}; };
PipelineTessellationStateCreateInfo tessellationState; PipelineTessellationStateCreateInfo tessellationState = new()
{
SType = StructureType.PipelineTessellationStateCreateInfo,
PatchControlPoints = PatchControlPoints,
};
PipelineRasterizationStateCreateInfo rasterizationState = new() PipelineRasterizationStateCreateInfo rasterizationState = new()
{ {
SType = StructureType.PipelineRasterizationStateCreateInfo, SType = StructureType.PipelineRasterizationStateCreateInfo,
DepthClampEnable = DepthClampEnable, DepthClampEnable = DepthClampEnable,
// When widelines feature is not supported it must be 1.0f, this will be ignored if Line Width dynamic state is supported RasterizerDiscardEnable = RasterizerDiscardEnable,
LineWidth = 1.0f, PolygonMode = PolygonMode,
LineWidth = LineWidth,
CullMode = CullMode,
FrontFace = FrontFace,
DepthBiasEnable = DepthBiasEnable,
}; };
PipelineViewportStateCreateInfo viewportState = new() PipelineViewportStateCreateInfo viewportState = new()
{ {
SType = StructureType.PipelineViewportStateCreateInfo, SType = StructureType.PipelineViewportStateCreateInfo,
ViewportCount = ViewportsCount,
ScissorCount = ScissorsCount,
}; };
if (gd.Capabilities.SupportsDepthClipControl) if (gd.Capabilities.SupportsDepthClipControl)
@@ -552,70 +494,64 @@ namespace Ryujinx.Graphics.Vulkan
AlphaToOneEnable = AlphaToOneEnable, AlphaToOneEnable = AlphaToOneEnable,
}; };
StencilOpState stencilFront = new(
StencilFrontFailOp,
StencilFrontPassOp,
StencilFrontDepthFailOp,
StencilFrontCompareOp);
StencilOpState stencilBack = new(
StencilBackFailOp,
StencilBackPassOp,
StencilBackDepthFailOp,
StencilBackCompareOp);
PipelineDepthStencilStateCreateInfo depthStencilState = new() PipelineDepthStencilStateCreateInfo depthStencilState = new()
{ {
SType = StructureType.PipelineDepthStencilStateCreateInfo, SType = StructureType.PipelineDepthStencilStateCreateInfo,
DepthBoundsTestEnable = DepthBoundsTestEnable, DepthTestEnable = DepthTestEnable,
DepthWriteEnable = DepthWriteEnable,
DepthCompareOp = DepthCompareOp,
DepthBoundsTestEnable = false,
StencilTestEnable = StencilTestEnable,
Front = stencilFront,
Back = stencilBack,
}; };
if (!_supportsExtDynamicState) uint blendEnables = 0;
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
{ {
rasterizationState.CullMode = CullMode; // Blend can't be enabled for integer formats, so let's make sure it is disabled.
rasterizationState.FrontFace = FrontFace; uint attachmentIntegerFormatMask = Internal.AttachmentIntegerFormatMask;
viewportState.ViewportCount = ViewportsCount; while (attachmentIntegerFormatMask != 0)
viewportState.ScissorCount = ScissorsCount;
StencilOpState stencilFront = new(
StencilFrontFailOp,
StencilFrontPassOp,
StencilFrontDepthFailOp,
StencilFrontCompareOp);
StencilOpState stencilBack = new(
StencilBackFailOp,
StencilBackPassOp,
StencilBackDepthFailOp,
StencilBackCompareOp);
depthStencilState.Front = stencilFront;
depthStencilState.Back = stencilBack;
depthStencilState.StencilTestEnable = StencilTestEnable;
depthStencilState.DepthTestEnable = DepthTestEnable;
depthStencilState.DepthWriteEnable = DepthWriteEnable;
depthStencilState.DepthCompareOp = DepthCompareOp;
}
if (!_supportsExtDynamicState2.ExtendedDynamicState2)
{
inputAssemblyState.PrimitiveRestartEnable = PrimitiveRestartEnable;
rasterizationState.DepthBiasEnable = DepthBiasEnable;
rasterizationState.RasterizerDiscardEnable = RasterizerDiscardEnable;
}
if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
{
tessellationState = new PipelineTessellationStateCreateInfo
{ {
SType = StructureType.PipelineTessellationStateCreateInfo, int i = BitOperations.TrailingZeroCount(attachmentIntegerFormatMask);
PatchControlPoints = PatchControlPoints,
}; if (Internal.ColorBlendAttachmentState[i].BlendEnable)
{
blendEnables |= 1u << i;
}
Internal.ColorBlendAttachmentState[i].BlendEnable = false;
attachmentIntegerFormatMask &= ~(1u << i);
}
} }
// Vendors other than NVIDIA have a bug where it enables logical operations even for float formats,
// so we need to force disable them here.
bool logicOpEnable = LogicOpEnable && (gd.Vendor == Vendor.Nvidia || Internal.LogicOpsAllowed);
PipelineColorBlendStateCreateInfo colorBlendState = new() PipelineColorBlendStateCreateInfo colorBlendState = new()
{ {
SType = StructureType.PipelineColorBlendStateCreateInfo, SType = StructureType.PipelineColorBlendStateCreateInfo,
LogicOpEnable = logicOpEnable,
LogicOp = LogicOp,
AttachmentCount = ColorBlendAttachmentStateCount, AttachmentCount = ColorBlendAttachmentStateCount,
PAttachments = pColorBlendAttachmentState, PAttachments = pColorBlendAttachmentState,
LogicOpEnable = LogicOpEnable,
}; };
if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp)
{
colorBlendState.LogicOp = LogicOp;
}
if (!AdvancedBlendSrcPreMultiplied || if (!AdvancedBlendSrcPreMultiplied ||
!AdvancedBlendDstPreMultiplied || !AdvancedBlendDstPreMultiplied ||
AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt) AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
@@ -631,99 +567,66 @@ namespace Ryujinx.Graphics.Vulkan
colorBlendState.PNext = &colorBlendAdvancedState; colorBlendState.PNext = &colorBlendAdvancedState;
} }
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop;
DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount]; DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount];
uint dynamicStatesCount = 7; int dynamicStatesCount = 7;
dynamicStates[0] = DynamicState.Viewport; dynamicStates[0] = DynamicState.Viewport;
dynamicStates[1] = DynamicState.Scissor; dynamicStates[1] = DynamicState.Scissor;
dynamicStates[2] = DynamicState.StencilCompareMask; dynamicStates[2] = DynamicState.DepthBias;
dynamicStates[3] = DynamicState.StencilWriteMask; dynamicStates[3] = DynamicState.StencilCompareMask;
dynamicStates[4] = DynamicState.StencilReference; dynamicStates[4] = DynamicState.StencilWriteMask;
dynamicStates[5] = DynamicState.BlendConstants; dynamicStates[5] = DynamicState.StencilReference;
dynamicStates[6] = DynamicState.DepthBias; dynamicStates[6] = DynamicState.BlendConstants;
if (!isMoltenVk) if (supportsExtDynamicState && (gd.SupportsMTL31 || !gd.IsMoltenVk))
{ {
//LineWidth dynamic state is only supported on macOS when using Metal Private API on newer version of MoltenVK // Requires Metal 3.1 and new MoltenVK, however extended dynamic states extension is not
dynamicStates[dynamicStatesCount++] = DynamicState.LineWidth; // available on older versions of MVK, so we can safely check only OS version.
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
} }
if (_supportsExtDynamicState) if (supportsFeedbackLoopDynamicState)
{
if (gd.SupportsMTL31 || !gd.IsMoltenVk)
{
// Requires Metal 3.1 and new MoltenVK, however extended dynamic states extension is not
// available on older versions of MVK, so we can safely check only OS version.
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
}
dynamicStates[0] = DynamicState.ViewportWithCountExt;
dynamicStates[1] = DynamicState.ScissorWithCountExt;
dynamicStates[dynamicStatesCount++] = DynamicState.CullModeExt;
dynamicStates[dynamicStatesCount++] = DynamicState.FrontFaceExt;
dynamicStates[dynamicStatesCount++] = DynamicState.DepthTestEnableExt;
dynamicStates[dynamicStatesCount++] = DynamicState.DepthWriteEnableExt;
dynamicStates[dynamicStatesCount++] = DynamicState.DepthCompareOpExt;
dynamicStates[dynamicStatesCount++] = DynamicState.StencilTestEnableExt;
dynamicStates[dynamicStatesCount++] = DynamicState.StencilOpExt;
dynamicStates[dynamicStatesCount++] = DynamicState.PrimitiveTopologyExt;
}
if (_supportsExtDynamicState2.ExtendedDynamicState2)
{
dynamicStates[dynamicStatesCount++] = DynamicState.DepthBiasEnableExt;
dynamicStates[dynamicStatesCount++] = DynamicState.RasterizerDiscardEnableExt;
dynamicStates[dynamicStatesCount++] = DynamicState.PrimitiveRestartEnableExt;
if (_supportsExtDynamicState2.ExtendedDynamicState2LogicOp)
{
dynamicStates[dynamicStatesCount++] = DynamicState.LogicOpExt;
}
if (_supportsExtDynamicState2.ExtendedDynamicState2PatchControlPoints)
{
dynamicStates[dynamicStatesCount++] = DynamicState.PatchControlPointsExt;
}
}
PipelineCreateFlags pipelineCreateFlags = 0;
if (gd.Capabilities.SupportsAttachmentFeedbackLoop && !_supportsFeedBackLoopDynamicState)
{
FeedbackLoopAspects aspects = FeedbackLoopAspects;
if ((aspects & FeedbackLoopAspects.Color) != 0)
{
pipelineCreateFlags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt;
}
if ((aspects & FeedbackLoopAspects.Depth) != 0)
{
pipelineCreateFlags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt;
}
}
if (_supportsFeedBackLoopDynamicState && FeedbackLoopDynamicState)
{ {
dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt; dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt;
FeedbackLoopDynamicState = false;
} }
PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = new() PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = new()
{ {
SType = StructureType.PipelineDynamicStateCreateInfo, SType = StructureType.PipelineDynamicStateCreateInfo,
DynamicStateCount = dynamicStatesCount, DynamicStateCount = (uint)dynamicStatesCount,
PDynamicStates = dynamicStates, PDynamicStates = dynamicStates,
}; };
PipelineCreateFlags flags = 0;
if (gd.Capabilities.SupportsAttachmentFeedbackLoop)
{
FeedbackLoopAspects aspects = FeedbackLoopAspects;
if ((aspects & FeedbackLoopAspects.Color) != 0)
{
flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt;
}
if ((aspects & FeedbackLoopAspects.Depth) != 0)
{
flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt;
}
}
GraphicsPipelineCreateInfo pipelineCreateInfo = new() GraphicsPipelineCreateInfo pipelineCreateInfo = new()
{ {
SType = StructureType.GraphicsPipelineCreateInfo, SType = StructureType.GraphicsPipelineCreateInfo,
Flags = flags,
StageCount = StagesCount, StageCount = StagesCount,
Flags = pipelineCreateFlags,
PStages = Stages.Pointer, PStages = Stages.Pointer,
PVertexInputState = &vertexInputState, PVertexInputState = &vertexInputState,
PInputAssemblyState = &inputAssemblyState, PInputAssemblyState = &inputAssemblyState,
PTessellationState = &tessellationState,
PViewportState = &viewportState, PViewportState = &viewportState,
PRasterizationState = &rasterizationState, PRasterizationState = &rasterizationState,
PMultisampleState = &multisampleState, PMultisampleState = &multisampleState,
@@ -734,11 +637,6 @@ namespace Ryujinx.Graphics.Vulkan
RenderPass = renderPass, RenderPass = renderPass,
}; };
if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
{
pipelineCreateInfo.PTessellationState = &tessellationState;
}
Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle); Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle);
if (throwOnError) if (throwOnError)
@@ -751,21 +649,21 @@ namespace Ryujinx.Graphics.Vulkan
return null; return null;
} }
// Restore previous blend enable values if we changed it.
while (blendEnables != 0)
{
int i = BitOperations.TrailingZeroCount(blendEnables);
Internal.ColorBlendAttachmentState[i].BlendEnable = true;
blendEnables &= ~(1u << i);
}
} }
pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle)); pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
program.AddGraphicsPipeline(ref Internal, pipeline); program.AddGraphicsPipeline(ref Internal, pipeline);
// Restore previous blend enable values if we changed it.
while (_blendEnables != 0)
{
int i = BitOperations.TrailingZeroCount(_blendEnables);
Internal.ColorBlendAttachmentState[i].BlendEnable = true;
_blendEnables &= ~(1u << i);
}
return pipeline; return pipeline;
} }
+21 -8
View File
@@ -11,17 +11,23 @@ namespace Ryujinx.Graphics.Vulkan
{ {
public ulong Id0; public ulong Id0;
public ulong Id1; public ulong Id1;
public ulong Id2; public ulong Id2;
public ulong Id3; public ulong Id3;
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id0 >> 38) & 0xFF); public ulong Id4;
private readonly uint VertexBindingDescriptionsCount => (byte)((Id0 >> 46) & 0xFF); public ulong Id5;
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id1 >> 8) & 0xFF); public ulong Id6;
private readonly bool HasDepthStencil => ((Id1 >> 63) & 0x1) != 0UL;
public ulong Id7;
public ulong Id8;
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id5 >> 38) & 0xFF);
private readonly uint VertexBindingDescriptionsCount => (byte)((Id5 >> 46) & 0xFF);
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id6 >> 8) & 0xFF);
private readonly bool HasDepthStencil => ((Id6 >> 63) & 0x1) != 0UL;
public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions; public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions;
public Array32<VertexInputBindingDescription> VertexBindingDescriptions; public Array33<VertexInputBindingDescription> VertexBindingDescriptions;
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState; public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
public Array9<Format> AttachmentFormats; public Array9<Format> AttachmentFormats;
public uint AttachmentIntegerFormatMask; public uint AttachmentIntegerFormatMask;
@@ -34,7 +40,9 @@ namespace Ryujinx.Graphics.Vulkan
public bool Equals(ref PipelineUid other) public bool Equals(ref PipelineUid other)
{ {
if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0))) if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0)) ||
!Unsafe.As<ulong, Vector256<byte>>(ref Id4).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id4)) ||
!Unsafe.As<ulong, Vector128<byte>>(ref Id7).Equals(Unsafe.As<ulong, Vector128<byte>>(ref other.Id7)))
{ {
return false; return false;
} }
@@ -72,7 +80,12 @@ namespace Ryujinx.Graphics.Vulkan
ulong hash64 = Id0 * 23 ^ ulong hash64 = Id0 * 23 ^
Id1 * 23 ^ Id1 * 23 ^
Id2 * 23 ^ Id2 * 23 ^
Id3 * 23; Id3 * 23 ^
Id4 * 23 ^
Id5 * 23 ^
Id6 * 23 ^
Id7 * 23 ^
Id8 * 23;
ReadOnlySpan<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = VertexAttributeDescriptions.AsSpan(); ReadOnlySpan<VertexInputAttributeDescription> vertexAttributeDescriptionsSpan = VertexAttributeDescriptions.AsSpan();
@@ -44,6 +44,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Ryujinx.SPB" />
<PackageReference Include="Silk.NET.Shaderc" ExcludeAssets="native" /> <PackageReference Include="Silk.NET.Shaderc" ExcludeAssets="native" />
<PackageReference Include="Silk.NET.Vulkan" /> <PackageReference Include="Silk.NET.Vulkan" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" /> <PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using PrimitiveTopology = Silk.NET.Vulkan.PrimitiveTopology;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
@@ -539,7 +538,7 @@ namespace Ryujinx.Graphics.Vulkan
public void CreateBackgroundComputePipeline() public void CreateBackgroundComputePipeline()
{ {
PipelineState pipeline = new(); PipelineState pipeline = new();
pipeline.Initialize(_gd.Capabilities); pipeline.Initialize();
pipeline.Stages[0] = _shaders[0].GetInfo(); pipeline.Stages[0] = _shaders[0].GetInfo();
pipeline.StagesCount = 1; pipeline.StagesCount = 1;
+1
View File
@@ -99,6 +99,7 @@ namespace Ryujinx.Graphics.Vulkan
DriverId.MesaNvk => "NVK", DriverId.MesaNvk => "NVK",
DriverId.ImaginationOpenSourceMesa => "Imagination (Open)", DriverId.ImaginationOpenSourceMesa => "Imagination (Open)",
DriverId.MesaHoneykrisp => "Honeykrisp", DriverId.MesaHoneykrisp => "Honeykrisp",
DriverId.MesaKosmickrisp => "KosmicKrisp",
_ => id.ToString(), _ => id.ToString(),
}; };
} }
@@ -71,10 +71,7 @@ namespace Ryujinx.Graphics.Vulkan
_buffer = autoBuffer; _buffer = autoBuffer;
if (!gd.Capabilities.SupportsExtendedDynamicState) state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
{
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
}
} }
return; return;
@@ -82,11 +79,8 @@ namespace Ryujinx.Graphics.Vulkan
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size); autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
if (!gd.Capabilities.SupportsExtendedDynamicState) // The original stride must be reapplied in case it was rewritten.
{ state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
// The original stride must be reapplied in case it was rewritten.
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
}
if (_offset >= size) if (_offset >= size)
{ {
@@ -101,7 +101,7 @@ namespace Ryujinx.Graphics.Vulkan
_strides[i] = strides[i]; _strides[i] = strides[i];
} }
if (_gd.Capabilities.SupportsExtendedDynamicState && (_gd.SupportsMTL31 || !_gd.IsMoltenVk)) if (_gd.Capabilities.SupportsExtendedDynamicState)
{ {
_gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2( _gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
cbs.CommandBuffer, cbs.CommandBuffer,
@@ -0,0 +1,54 @@
using System;
using System.IO;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Vulkan
{
[SupportedOSPlatform("macos")]
public static class VulkanDriver
{
private static string GetIcdPath(string fileName)
{
string baseDir = AppContext.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
string contentsDir = Path.GetDirectoryName(baseDir)!;
string[] searchPaths =
[
// .app bundle:
Path.Combine(contentsDir, "Resources", "vulkan", "icd.d", fileName),
// Local build:
Path.Combine(contentsDir, fileName)
];
foreach (string icdPath in searchPaths)
{
if (File.Exists(icdPath))
{
return icdPath;
}
}
throw new FileNotFoundException(
$"{fileName} not found. Searched:\n{string.Join(Environment.NewLine, searchPaths)}");
}
public static void MoltenVK()
{
Environment.SetEnvironmentVariable("MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", "1");
Environment.SetEnvironmentVariable("MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE", "0");
Environment.SetEnvironmentVariable("MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", "0");
Environment.SetEnvironmentVariable("MVK_CONFIG_RESUME_LOST_DEVICE", "1");
Environment.SetEnvironmentVariable("VK_DRIVER_FILES", GetIcdPath("MoltenVK_icd.json"));
Console.WriteLine($"[MoltenVK] VK_DRIVER_FILES just set to: {Environment.GetEnvironmentVariable("VK_DRIVER_FILES")}");
}
public static void KosmicKrisp()
{
Environment.SetEnvironmentVariable("VK_DRIVER_FILES", GetIcdPath("libkosmickrisp_icd.json"));
Console.WriteLine($"[KosmicKrisp] VK_DRIVER_FILES just set to: {Environment.GetEnvironmentVariable("VK_DRIVER_FILES")}");
}
}
}
@@ -5,7 +5,6 @@ using Silk.NET.Core;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT; using Silk.NET.Vulkan.Extensions.EXT;
using Silk.NET.Vulkan.Extensions.KHR; using Silk.NET.Vulkan.Extensions.KHR;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -14,10 +13,11 @@ namespace Ryujinx.Graphics.Vulkan
{ {
public unsafe static class VulkanInitialization public unsafe static class VulkanInitialization
{ {
private static Version32 Version14 => new(1, 4, 0);
private const uint InvalidIndex = uint.MaxValue; private const uint InvalidIndex = uint.MaxValue;
private static readonly uint _minimalVulkanVersion = Vk.Version11.Value; private static readonly uint _minimalVulkanVersion = Vk.Version11.Value;
private static readonly uint _minimalInstanceVulkanVersion = Vk.Version12.Value; private static readonly uint _maximumVulkanVersion = Version14.Value;
private static readonly uint _maximumVulkanVersion = Vk.Version12.Value;
private const string AppName = "Ryujinx.Graphics.Vulkan"; private const string AppName = "Ryujinx.Graphics.Vulkan";
private const int QueuesCount = 2; private const int QueuesCount = 2;
@@ -25,7 +25,6 @@ namespace Ryujinx.Graphics.Vulkan
[ [
ExtConditionalRendering.ExtensionName, ExtConditionalRendering.ExtensionName,
ExtExtendedDynamicState.ExtensionName, ExtExtendedDynamicState.ExtensionName,
ExtExtendedDynamicState2.ExtensionName,
ExtTransformFeedback.ExtensionName, ExtTransformFeedback.ExtensionName,
KhrDrawIndirectCount.ExtensionName, KhrDrawIndirectCount.ExtensionName,
KhrPushDescriptor.ExtensionName, KhrPushDescriptor.ExtensionName,
@@ -60,7 +59,7 @@ namespace Ryujinx.Graphics.Vulkan
internal static VulkanInstance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions) internal static VulkanInstance CreateInstance(Vk api, GraphicsDebugLevel logLevel, string[] requiredExtensions)
{ {
List<string> enabledLayers = new(); List<string> enabledLayers = [];
IReadOnlySet<string> instanceExtensions = VulkanInstance.GetInstanceExtensions(api); IReadOnlySet<string> instanceExtensions = VulkanInstance.GetInstanceExtensions(api);
IReadOnlySet<string> instanceLayers = VulkanInstance.GetInstanceLayers(api); IReadOnlySet<string> instanceLayers = VulkanInstance.GetInstanceLayers(api);
@@ -89,7 +88,7 @@ namespace Ryujinx.Graphics.Vulkan
enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray(); enabledExtensions = enabledExtensions.Append(ExtDebugUtils.ExtensionName).ToArray();
} }
IntPtr appName = Marshal.StringToHGlobalAnsi(AppName); nint appName = Marshal.StringToHGlobalAnsi(AppName);
ApplicationInfo applicationInfo = new() ApplicationInfo applicationInfo = new()
{ {
@@ -169,7 +168,7 @@ namespace Ryujinx.Graphics.Vulkan
internal static DeviceInfo[] GetSuitablePhysicalDevices(Vk api) internal static DeviceInfo[] GetSuitablePhysicalDevices(Vk api)
{ {
IntPtr appName = Marshal.StringToHGlobalAnsi(AppName); nint appName = Marshal.StringToHGlobalAnsi(AppName);
ApplicationInfo applicationInfo = new() ApplicationInfo applicationInfo = new()
{ {
@@ -198,13 +197,6 @@ namespace Ryujinx.Graphics.Vulkan
using VulkanInstance instance = rawInstance; using VulkanInstance instance = rawInstance;
// We currently assume that the instance is compatible with Vulkan 1.2
// TODO: Remove this once we relax our initialization codepaths.
if (instance.InstanceVersion < _minimalInstanceVulkanVersion)
{
return [];
}
instance.EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices).ThrowOnError(); instance.EnumeratePhysicalDevices(out VulkanPhysicalDevice[] physicalDevices).ThrowOnError();
List<DeviceInfo> deviceInfos = []; List<DeviceInfo> deviceInfos = [];
@@ -320,17 +312,6 @@ namespace Ryujinx.Graphics.Vulkan
features2.PNext = &supportedFeaturesCustomBorderColor; features2.PNext = &supportedFeaturesCustomBorderColor;
} }
PhysicalDeviceExtendedDynamicState2FeaturesEXT supportedFeaturesExtExtendedDynamicState2 = new()
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
PNext = features2.PNext,
};
if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName))
{
features2.PNext = &supportedFeaturesExtExtendedDynamicState2;
}
PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT supportedFeaturesPrimitiveTopologyListRestart = new() PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT supportedFeaturesPrimitiveTopologyListRestart = new()
{ {
SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt, SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
@@ -398,7 +379,7 @@ namespace Ryujinx.Graphics.Vulkan
features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout; features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout;
} }
PhysicalDevicePageableDeviceLocalMemoryFeaturesEXT supportedPageableDeviceLocalMemoryFeatures = new() PhysicalDevicePageableDeviceLocalMemoryFeaturesEXT supportedFeaturesPageableDeviceLocalMemory = new()
{ {
SType = StructureType.PhysicalDevicePageableDeviceLocalMemoryFeaturesExt, SType = StructureType.PhysicalDevicePageableDeviceLocalMemoryFeaturesExt,
PNext = features2.PNext, PNext = features2.PNext,
@@ -406,10 +387,10 @@ namespace Ryujinx.Graphics.Vulkan
if (physicalDevice.IsDeviceExtensionPresent(ExtPageableDeviceLocalMemory.ExtensionName)) if (physicalDevice.IsDeviceExtensionPresent(ExtPageableDeviceLocalMemory.ExtensionName))
{ {
features2.PNext = &supportedPageableDeviceLocalMemoryFeatures; features2.PNext = &supportedFeaturesPageableDeviceLocalMemory;
} }
PhysicalDeviceMemoryPriorityFeaturesEXT supportedDeviceMemoryPriorityFeatures = new() PhysicalDeviceMemoryPriorityFeaturesEXT supportedFeaturesDeviceMemoryPriority = new()
{ {
SType = StructureType.PhysicalDeviceMemoryPriorityFeaturesExt, SType = StructureType.PhysicalDeviceMemoryPriorityFeaturesExt,
PNext = features2.PNext, PNext = features2.PNext,
@@ -417,7 +398,7 @@ namespace Ryujinx.Graphics.Vulkan
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_memory_priority")) if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_memory_priority"))
{ {
features2.PNext = &supportedDeviceMemoryPriorityFeatures; features2.PNext = &supportedFeaturesDeviceMemoryPriority;
} }
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new() PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
@@ -428,6 +409,22 @@ namespace Ryujinx.Graphics.Vulkan
features2.PNext = &supportedPhysicalDeviceVulkan12Features; features2.PNext = &supportedPhysicalDeviceVulkan12Features;
PhysicalDeviceVulkan13Features supportedPhysicalDeviceVulkan13Features = new()
{
SType = StructureType.PhysicalDeviceVulkan13Features,
PNext = features2.PNext,
};
features2.PNext = &supportedPhysicalDeviceVulkan13Features;
PhysicalDeviceVulkan14Features supportedPhysicalDeviceVulkan14Features = new()
{
SType = StructureType.PhysicalDeviceVulkan14Features,
PNext = features2.PNext,
};
features2.PNext = &supportedPhysicalDeviceVulkan14Features;
api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2); api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2);
PhysicalDeviceFeatures supportedFeatures = features2.Features; PhysicalDeviceFeatures supportedFeatures = features2.Features;
@@ -455,7 +452,6 @@ namespace Ryujinx.Graphics.Vulkan
TessellationShader = supportedFeatures.TessellationShader, TessellationShader = supportedFeatures.TessellationShader,
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics, VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
RobustBufferAccess = useRobustBufferAccess, RobustBufferAccess = useRobustBufferAccess,
WideLines = supportedFeatures.WideLines,
SampleRateShading = supportedFeatures.SampleRateShading, SampleRateShading = supportedFeatures.SampleRateShading,
ShaderStorageImageExtendedFormats = supportedFeatures.ShaderStorageImageExtendedFormats, ShaderStorageImageExtendedFormats = supportedFeatures.ShaderStorageImageExtendedFormats,
}; };
@@ -508,20 +504,6 @@ namespace Ryujinx.Graphics.Vulkan
pExtendedFeatures = &featuresExtendedDynamicState; pExtendedFeatures = &featuresExtendedDynamicState;
if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName))
{
var featuresExtendedDynamicState2 = new PhysicalDeviceExtendedDynamicState2FeaturesEXT()
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
PNext = pExtendedFeatures,
ExtendedDynamicState2 = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2,
ExtendedDynamicState2LogicOp = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2LogicOp,
ExtendedDynamicState2PatchControlPoints = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints,
};
pExtendedFeatures = &featuresExtendedDynamicState2;
}
PhysicalDeviceVulkan11Features featuresVk11 = new() PhysicalDeviceVulkan11Features featuresVk11 = new()
{ {
SType = StructureType.PhysicalDeviceVulkan11Features, SType = StructureType.PhysicalDeviceVulkan11Features,
@@ -546,6 +528,24 @@ namespace Ryujinx.Graphics.Vulkan
pExtendedFeatures = &featuresVk12; pExtendedFeatures = &featuresVk12;
PhysicalDeviceVulkan13Features featuresVk13 = new()
{
SType = StructureType.PhysicalDeviceVulkan13Features,
PNext = pExtendedFeatures,
/* Vulkan 1.3 features here */
};
pExtendedFeatures = &featuresVk13;
PhysicalDeviceVulkan13Features featuresVk14 = new()
{
SType = StructureType.PhysicalDeviceVulkan14Features,
PNext = pExtendedFeatures,
/* Vulkan 1.4 features here */
};
pExtendedFeatures = &featuresVk14;
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8")) if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"))
{ {
PhysicalDeviceIndexTypeUint8FeaturesEXT featuresIndexU8 = new() PhysicalDeviceIndexTypeUint8FeaturesEXT featuresIndexU8 = new()
@@ -625,7 +625,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
if (physicalDevice.IsDeviceExtensionPresent(ExtPageableDeviceLocalMemory.ExtensionName) && if (physicalDevice.IsDeviceExtensionPresent(ExtPageableDeviceLocalMemory.ExtensionName) &&
supportedPageableDeviceLocalMemoryFeatures.PageableDeviceLocalMemory) supportedFeaturesPageableDeviceLocalMemory.PageableDeviceLocalMemory)
{ {
PhysicalDevicePageableDeviceLocalMemoryFeaturesEXT featuresPageableDeviceLocalMemory = new() PhysicalDevicePageableDeviceLocalMemoryFeaturesEXT featuresPageableDeviceLocalMemory = new()
{ {
@@ -638,16 +638,16 @@ namespace Ryujinx.Graphics.Vulkan
} }
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_memory_priority") && if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_memory_priority") &&
supportedDeviceMemoryPriorityFeatures.MemoryPriority) supportedFeaturesDeviceMemoryPriority.MemoryPriority)
{ {
PhysicalDeviceMemoryPriorityFeaturesEXT featuresDeviceMemoryPriority = new() PhysicalDeviceMemoryPriorityFeaturesEXT featuresMemoryPriority = new()
{ {
SType = StructureType.PhysicalDeviceMemoryPriorityFeaturesExt, SType = StructureType.PhysicalDeviceMemoryPriorityFeaturesExt,
PNext = pExtendedFeatures, PNext = pExtendedFeatures,
MemoryPriority = true, MemoryPriority = true,
}; };
pExtendedFeatures = &featuresDeviceMemoryPriority; pExtendedFeatures = &featuresMemoryPriority;
} }
string[] enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray(); string[] enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
@@ -13,7 +13,6 @@ namespace Ryujinx.Graphics.Vulkan
{ {
private readonly Vk _api; private readonly Vk _api;
public readonly Instance Instance; public readonly Instance Instance;
public readonly Version32 InstanceVersion;
private bool _disposed; private bool _disposed;
@@ -21,22 +20,6 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_api = api; _api = api;
Instance = instance; Instance = instance;
if (api.GetInstanceProcAddr(instance, "vkEnumerateInstanceVersion") == nint.Zero)
{
InstanceVersion = Vk.Version10;
}
else
{
uint rawInstanceVersion = 0;
if (api.EnumerateInstanceVersion(ref rawInstanceVersion) != Result.Success)
{
rawInstanceVersion = Vk.Version11.Value;
}
InstanceVersion = (Version32)rawInstanceVersion;
}
} }
public static Result Create(Vk api, ref InstanceCreateInfo createInfo, out VulkanInstance instance) public static Result Create(Vk api, ref InstanceCreateInfo createInfo, out VulkanInstance instance)
+16 -36
View File
@@ -3,7 +3,6 @@ using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Graphics.Vulkan.Queries; using Ryujinx.Graphics.Vulkan.Queries;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.EXT; using Silk.NET.Vulkan.Extensions.EXT;
@@ -39,7 +38,6 @@ namespace Ryujinx.Graphics.Vulkan
internal KhrSwapchain SwapchainApi { get; private set; } internal KhrSwapchain SwapchainApi { get; private set; }
internal ExtConditionalRendering ConditionalRenderingApi { get; private set; } internal ExtConditionalRendering ConditionalRenderingApi { get; private set; }
internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; } internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; }
internal ExtExtendedDynamicState2 ExtendedDynamicState2Api { get; private set; }
internal KhrPushDescriptor PushDescriptorApi { get; private set; } internal KhrPushDescriptor PushDescriptorApi { get; private set; }
internal ExtTransformFeedback TransformFeedbackApi { get; private set; } internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; } internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
@@ -98,6 +96,7 @@ namespace Ryujinx.Graphics.Vulkan
internal bool IsIntelArc { get; private set; } internal bool IsIntelArc { get; private set; }
internal bool IsQualcommProprietary { get; private set; } internal bool IsQualcommProprietary { get; private set; }
internal bool IsMoltenVk { get; private set; } internal bool IsMoltenVk { get; private set; }
internal bool IsKosmicKrisp { get; private set; }
internal bool SupportsMTL31 { get; private set; } internal bool SupportsMTL31 { get; private set; }
internal bool IsTBDR { get; private set; } internal bool IsTBDR { get; private set; }
internal bool IsSharedMemory { get; private set; } internal bool IsSharedMemory { get; private set; }
@@ -112,7 +111,7 @@ namespace Ryujinx.Graphics.Vulkan
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured; public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
public VulkanRenderer(Vk api, Func<Instance, Vk, SurfaceKHR> surfaceFunc, Func<string[]> requiredExtensionsFunc, string preferredGpuId) public VulkanRenderer(Vk api, Func<Instance, Vk, SurfaceKHR> surfaceFunc, Func<string[]> requiredExtensionsFunc, string preferredGpuId, TranslationLayer translationLayer)
{ {
_getSurface = surfaceFunc; _getSurface = surfaceFunc;
_getRequiredExtensions = requiredExtensionsFunc; _getRequiredExtensions = requiredExtensionsFunc;
@@ -122,12 +121,20 @@ namespace Ryujinx.Graphics.Vulkan
Textures = []; Textures = [];
Samplers = []; Samplers = [];
// MoltenVK is required for any device running < macOS 26, even Intel and AMD vendors.
// KosmicKrisp, a Vulkan conformant implementation running on top of Metal 4, requires macOS 26.
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
{ {
MVKInitialization.Initialize(); if (translationLayer == TranslationLayer.MoltenVK)
{
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors. VulkanDriver.MoltenVK();
IsMoltenVk = true; IsMoltenVk = true;
}
if (translationLayer == TranslationLayer.KosmicKrisp)
{
VulkanDriver.KosmicKrisp();
IsKosmicKrisp = true;
}
} }
SupportsMTL31 = OperatingSystem.IsMacOSVersionAtLeast(14); SupportsMTL31 = OperatingSystem.IsMacOSVersionAtLeast(14);
@@ -147,11 +154,6 @@ namespace Ryujinx.Graphics.Vulkan
ExtendedDynamicStateApi = extendedDynamicStateApi; ExtendedDynamicStateApi = extendedDynamicStateApi;
} }
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExtendedDynamicState2 extendedDynamicState2Api))
{
ExtendedDynamicState2Api = extendedDynamicState2Api;
}
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi)) if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi))
{ {
PushDescriptorApi = pushDescriptorApi; PushDescriptorApi = pushDescriptorApi;
@@ -254,11 +256,6 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt, SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
}; };
PhysicalDeviceExtendedDynamicState2FeaturesEXT featuresExtendedDynamicState2 = new()
{
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
};
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2 = new() PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2 = new()
{ {
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt, SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
@@ -299,12 +296,6 @@ namespace Ryujinx.Graphics.Vulkan
features2.PNext = &featuresPrimitiveTopologyListRestart; features2.PNext = &featuresPrimitiveTopologyListRestart;
} }
if (_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName))
{
featuresExtendedDynamicState2.PNext = features2.PNext;
features2.PNext = &featuresExtendedDynamicState2;
}
if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2")) if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
{ {
featuresRobustness2.PNext = features2.PNext; featuresRobustness2.PNext = features2.PNext;
@@ -445,10 +436,6 @@ namespace Ryujinx.Graphics.Vulkan
properties.Limits.FramebufferDepthSampleCounts & properties.Limits.FramebufferDepthSampleCounts &
properties.Limits.FramebufferStencilSampleCounts; properties.Limits.FramebufferStencilSampleCounts;
// Temporarily disable this, can be added back at a later date, make it easy to re-enable.
// Disabled because currently causing Device Lost error on NVIDIA.
featuresExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints = false;
Capabilities = new HardwareCapabilities( Capabilities = new HardwareCapabilities(
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"), _physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"),
supportsCustomBorderColor, supportsCustomBorderColor,
@@ -465,8 +452,6 @@ namespace Ryujinx.Graphics.Vulkan
features2.Features.ShaderStorageImageMultisample, features2.Features.ShaderStorageImageMultisample,
_physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
featuresExtendedDynamicState2,
_physicalDevice.PhysicalDeviceProperties.Limits.MaxTessellationPatchSize,
features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue
featuresRobustness2.NullDescriptor || IsMoltenVk, featuresRobustness2.NullDescriptor || IsMoltenVk,
supportsPushDescriptors, supportsPushDescriptors,
@@ -482,7 +467,6 @@ namespace Ryujinx.Graphics.Vulkan
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"), _physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName), _physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl, supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
_physicalDevice.PhysicalDeviceFeatures.WideLines,
supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout && IsFeedbackLoopDevice, supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout && IsFeedbackLoopDevice,
supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState && IsFeedbackLoopDevice, supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState && IsFeedbackLoopDevice,
propertiesSubgroup.SubgroupSize, propertiesSubgroup.SubgroupSize,
@@ -822,10 +806,6 @@ namespace Ryujinx.Graphics.Vulkan
supportsViewportSwizzle: false, supportsViewportSwizzle: false,
supportsIndirectParameters: true, supportsIndirectParameters: true,
supportsDepthClipControl: Capabilities.SupportsDepthClipControl, supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
supportsExtendedDynamicState: Capabilities.SupportsExtendedDynamicState,
supportsExtendedDynamicState2: Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2,
supportsLogicOpDynamicState: Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp,
supportsPatchControlPointsDynamicState: Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints,
uniformBufferSetIndex: PipelineBase.UniformSetIndex, uniformBufferSetIndex: PipelineBase.UniformSetIndex,
storageBufferSetIndex: PipelineBase.StorageSetIndex, storageBufferSetIndex: PipelineBase.StorageSetIndex,
textureSetIndex: PipelineBase.TextureSetIndex, textureSetIndex: PipelineBase.TextureSetIndex,
@@ -870,14 +850,14 @@ namespace Ryujinx.Graphics.Vulkan
/// <summary> /// <summary>
/// Gets the available Vulkan devices using the default Vulkan API /// Gets the available Vulkan devices using the default Vulkan API
/// object returned by <see cref="Vk.GetApi()"/> /// object returned by <see cref="VulkanSpbApi.GetApiFromSpb()"/>
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static DeviceInfo[] GetPhysicalDevices() public static DeviceInfo[] GetPhysicalDevices()
{ {
try try
{ {
return VulkanInitialization.GetSuitablePhysicalDevices(Vk.GetApi()); return VulkanInitialization.GetSuitablePhysicalDevices(VulkanSpbApi.GetApiFromSpb());
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -0,0 +1,34 @@
using Silk.NET.Core.Contexts;
using Silk.NET.Vulkan;
using SPB.Graphics.Vulkan;
namespace Ryujinx.Graphics.Vulkan
{
public static class VulkanSpbApi
{
public static Vk GetApiFromSpb()
{
LamdaNativeContext baseCtx = new(VulkanHelper.GetProcAddress);
MultiNativeContext ctx = new(baseCtx, null);
Vk ret = new(ctx);
ctx.Contexts[1] = new LamdaNativeContext(x =>
{
if (x.EndsWith("ProcAddr"))
{
return default;
}
nint ptr = ret.GetDeviceProcAddr(ret.CurrentDevice.GetValueOrDefault(), x);
if (ptr != default)
{
return ptr;
}
return ret.GetInstanceProcAddr(ret.CurrentInstance.GetValueOrDefault(), x);
});
return ret;
}
}
}
@@ -26,12 +26,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
{ {
MemoryArrange.MemoryArrange4GiB or MemoryArrange.MemoryArrange4GiB or
MemoryArrange.MemoryArrange4GiBSystemDev or MemoryArrange.MemoryArrange4GiBSystemDev or
MemoryArrange.MemoryArrange6GiBAppletDev => 3236 * MiB, MemoryArrange.MemoryArrange6GiBAppletDev => 3173 * MiB,
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB, MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
MemoryArrange.MemoryArrange6GiB => 4867 * MiB, MemoryArrange.MemoryArrange6GiB => 4804 * MiB,
MemoryArrange.MemoryArrange8GiB => 6915 * MiB, MemoryArrange.MemoryArrange8GiB => 6852 * MiB,
MemoryArrange.MemoryArrange10GiB => 8963 * MiB, MemoryArrange.MemoryArrange10GiB => 8900 * MiB,
MemoryArrange.MemoryArrange12GiB => 11011 * MiB, MemoryArrange.MemoryArrange12GiB => 10948 * MiB,
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."), _ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
}; };
} }
@@ -203,9 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
heapRegion.Size = memConfig switch { heapRegion.Size = memConfig switch {
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u, MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u, MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
MemoryConfiguration.MemoryConfiguration10GiB => 0x200000000u,
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u, MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
MemoryConfiguration.MemoryConfiguration12GiB => 0x200000000u,
_ => 0x180000000u _ => 0x180000000u
}; };
stackRegion.Size = 0; stackRegion.Size = 0;
@@ -240,9 +238,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
heapRegion.Size = memConfig switch { heapRegion.Size = memConfig switch {
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u, MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u, MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
MemoryConfiguration.MemoryConfiguration10GiB => 0x200000000u,
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u, MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
MemoryConfiguration.MemoryConfiguration12GiB => 0x200000000u,
_ => 0x180000000u _ => 0x180000000u
}; };
stackRegion.Size = 1UL << (addressSpaceWidth - 8); stackRegion.Size = 1UL << (addressSpaceWidth - 8);
@@ -261,9 +257,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
heapRegion.Size = memConfig switch { heapRegion.Size = memConfig switch {
MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u, MemoryConfiguration.MemoryConfiguration8GiB => 0x200000000u,
MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u, MemoryConfiguration.MemoryConfiguration10GiB when !isHeapLimited => 0x280000000u,
MemoryConfiguration.MemoryConfiguration10GiB => 0x200000000u,
MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u, MemoryConfiguration.MemoryConfiguration12GiB when !isHeapLimited => 0x300000000u,
MemoryConfiguration.MemoryConfiguration12GiB => 0x200000000u,
_ => 0x180000000u _ => 0x180000000u
}; };
stackRegion.Size = 0x80000000; stackRegion.Size = 0x80000000;
@@ -21,21 +21,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
return ResultCode.Success; return ResultCode.Success;
} }
[CommandCmif(3)] // 20.0.0+
// CreateLibraryAppletEx(u32, u32, u64) -> object<nn::am::service::ILibraryAppletAccessor>
public ResultCode CreateLibraryAppletEx(ServiceCtx context)
{
AppletId appletId = (AppletId)context.RequestData.ReadInt32();
_ = context.RequestData.ReadInt32(); // libraryAppletMode
_ = context.RequestData.ReadUInt64(); // threadId
MakeObject(context, new ILibraryAppletAccessor(appletId, context.Device.System));
return ResultCode.Success;
}
[CommandCmif(10)] [CommandCmif(10)]
// CreateStorage(u64) -> object<nn::am::service::IStorage> // CreateStorage(u64) -> object<nn::am::service::IStorage>
public ResultCode CreateStorage(ServiceCtx context) public ResultCode CreateStorage(ServiceCtx context)
@@ -7,7 +7,6 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Loaders.Processes.Extensions;
using System.Collections.Concurrent; using System.Collections.Concurrent;
@@ -24,62 +23,7 @@ namespace Ryujinx.HLE.Loaders.Processes
private ulong _latestPid; private ulong _latestPid;
private readonly object _pidLock = new(); public ProcessResult ActiveApplication => _processesByPid[_latestPid];
#nullable enable
public ProcessResult? ActiveApplication
{
get
{
lock (_pidLock)
{
// Check if _latestPid is still valid
if (_latestPid == 0)
{
return null;
}
// Verify process still exists in kernel (authoritative source)
if (!_device.System.KernelContext.Processes.TryGetValue(_latestPid, out HOS.Kernel.Process.KProcess? kernelProcess))
{
// Process no longer exists in kernel, clear stale state
Logger.Warning?.Print(LogClass.Loader,
$"ActiveApplication PID {_latestPid} no longer exists in kernel, clearing stale state");
_processesByPid.TryRemove(_latestPid, out _);
_latestPid = 0;
return null;
}
// Verify process still exists in ProcessLoader's dictionary
if (_processesByPid.TryGetValue(_latestPid, out ProcessResult? processResult))
{
// Additional check: verify process state
if (kernelProcess.State == HOS.Kernel.Process.ProcessState.Exited ||
kernelProcess.State == HOS.Kernel.Process.ProcessState.Exiting)
{
Logger.Warning?.Print(LogClass.Loader,
$"ActiveApplication PID {_latestPid} is in state {kernelProcess.State}, clearing");
_processesByPid.TryRemove(_latestPid, out _);
_latestPid = 0;
return null;
}
return processResult;
}
// Fallback: clear stale PID if not in our dictionary
Logger.Warning?.Print(LogClass.Loader,
$"ActiveApplication PID {_latestPid} not in ProcessLoader dictionary, clearing");
_latestPid = 0;
return null;
}
}
}
#nullable disable
public ProcessLoader(Switch device) public ProcessLoader(Switch device)
{ {
@@ -282,7 +226,7 @@ namespace Ryujinx.HLE.Loaders.Processes
} }
// Explicitly null TitleId to disable the shader cache. // Explicitly null TitleId to disable the shader cache.
GraphicsConfig.TitleId = null; Graphics.Gpu.GraphicsConfig.TitleId = null;
_device.Gpu.HostInitalized.Set(); _device.Gpu.HostInitalized.Set();
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device, ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
@@ -321,37 +265,5 @@ namespace Ryujinx.HLE.Loaders.Processes
return false; return false;
} }
/// <summary>
/// Clears a specific process from the ProcessLoader's tracking.
/// This should be called when a process exits or is terminated.
/// </summary>
/// <param name="pid">The process ID to clear</param>
public void ClearProcess(ulong pid)
{
lock (_pidLock)
{
if (_processesByPid.TryRemove(pid, out _))
{
if (_latestPid == pid)
{
_latestPid = 0;
}
}
}
}
/// <summary>
/// Clears all processes from the ProcessLoader's tracking.
/// This should be called during system shutdown.
/// </summary>
public void ClearAllProcesses()
{
lock (_pidLock)
{
_processesByPid.Clear();
_latestPid = 0;
}
}
} }
} }
-1
View File
@@ -208,7 +208,6 @@ namespace Ryujinx.HLE
{ {
if (disposing) if (disposing)
{ {
Processes.ClearAllProcesses();
System.Dispose(); System.Dispose();
AudioDeviceDriver.Dispose(); AudioDeviceDriver.Dispose();
FileSystem.Dispose(); FileSystem.Dispose();
@@ -439,6 +439,11 @@ namespace Ryujinx.UI.Common.Configuration
/// </summary> /// </summary>
public GraphicsBackend GraphicsBackend { get; set; } public GraphicsBackend GraphicsBackend { get; set; }
/// <summary>
/// Vulkan translation layer
/// </summary>
public TranslationLayer TranslationLayer { get; set; }
/// <summary> /// <summary>
/// Preferred GPU /// Preferred GPU
/// </summary> /// </summary>
@@ -587,6 +587,11 @@ namespace Ryujinx.UI.Common.Configuration
/// </summary> /// </summary>
public ReactiveObject<GraphicsBackend> GraphicsBackend { get; private set; } public ReactiveObject<GraphicsBackend> GraphicsBackend { get; private set; }
/// <summary>
/// Vulkan translation layer
/// </summary>
public ReactiveObject<TranslationLayer> TranslationLayer { get; private set; }
/// <summary> /// <summary>
/// Applies anti-aliasing to the renderer. /// Applies anti-aliasing to the renderer.
/// </summary> /// </summary>
@@ -639,6 +644,8 @@ namespace Ryujinx.UI.Common.Configuration
EnableTextureRecompression.Event += static (_, e) => LogValueChange(e, nameof(EnableTextureRecompression)); EnableTextureRecompression.Event += static (_, e) => LogValueChange(e, nameof(EnableTextureRecompression));
GraphicsBackend = new ReactiveObject<GraphicsBackend>(); GraphicsBackend = new ReactiveObject<GraphicsBackend>();
GraphicsBackend.Event += static (_, e) => LogValueChange(e, nameof(GraphicsBackend)); GraphicsBackend.Event += static (_, e) => LogValueChange(e, nameof(GraphicsBackend));
TranslationLayer = new ReactiveObject<TranslationLayer>();
TranslationLayer.Event += static (_, e) => LogValueChange(e, nameof(TranslationLayer));
PreferredGpu = new ReactiveObject<string>(); PreferredGpu = new ReactiveObject<string>();
PreferredGpu.Event += static (_, e) => LogValueChange(e, nameof(PreferredGpu)); PreferredGpu.Event += static (_, e) => LogValueChange(e, nameof(PreferredGpu));
EnableMacroHLE = new ReactiveObject<bool>(); EnableMacroHLE = new ReactiveObject<bool>();
@@ -935,6 +942,7 @@ namespace Ryujinx.UI.Common.Configuration
ControllerConfig = [], ControllerConfig = [],
InputConfig = Hid.InputConfig, InputConfig = Hid.InputConfig,
GraphicsBackend = Graphics.GraphicsBackend, GraphicsBackend = Graphics.GraphicsBackend,
TranslationLayer = Graphics.TranslationLayer,
PreferredGpu = Graphics.PreferredGpu, PreferredGpu = Graphics.PreferredGpu,
MultiplayerLanInterfaceId = Multiplayer.LanInterfaceId, MultiplayerLanInterfaceId = Multiplayer.LanInterfaceId,
MultiplayerMode = Multiplayer.Mode, MultiplayerMode = Multiplayer.Mode,
@@ -958,6 +966,7 @@ namespace Ryujinx.UI.Common.Configuration
Graphics.MaxAnisotropy.Value = -1.0f; Graphics.MaxAnisotropy.Value = -1.0f;
Graphics.AspectRatio.Value = AspectRatio.Fixed16x9; Graphics.AspectRatio.Value = AspectRatio.Fixed16x9;
Graphics.GraphicsBackend.Value = DefaultGraphicsBackend(); Graphics.GraphicsBackend.Value = DefaultGraphicsBackend();
Graphics.TranslationLayer.Value = TranslationLayer.MoltenVK;
Graphics.PreferredGpu.Value = ""; Graphics.PreferredGpu.Value = "";
Graphics.ShadersDumpPath.Value = ""; Graphics.ShadersDumpPath.Value = "";
Graphics.TexturesDumpPath.Value = ""; Graphics.TexturesDumpPath.Value = "";
@@ -1806,6 +1815,15 @@ namespace Ryujinx.UI.Common.Configuration
configurationFileUpdated = true; configurationFileUpdated = true;
} }
if (configurationFileFormat.Version < 62)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 62.");
configurationFileFormat.TranslationLayer = TranslationLayer.MoltenVK;
configurationFileUpdated = true;
}
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScale.Value = configurationFileFormat.ResScale;
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
@@ -1818,6 +1836,7 @@ namespace Ryujinx.UI.Common.Configuration
Graphics.EnableTextureRealTimeEdit.Value = configurationFileFormat.GraphicsEnableTextureRealTimeEdit; Graphics.EnableTextureRealTimeEdit.Value = configurationFileFormat.GraphicsEnableTextureRealTimeEdit;
Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading; Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
Graphics.GraphicsBackend.Value = configurationFileFormat.GraphicsBackend; Graphics.GraphicsBackend.Value = configurationFileFormat.GraphicsBackend;
Graphics.TranslationLayer.Value = configurationFileFormat.TranslationLayer;
Graphics.PreferredGpu.Value = configurationFileFormat.PreferredGpu; Graphics.PreferredGpu.Value = configurationFileFormat.PreferredGpu;
Graphics.AntiAliasing.Value = configurationFileFormat.AntiAliasing; Graphics.AntiAliasing.Value = configurationFileFormat.AntiAliasing;
Graphics.ScalingFilter.Value = configurationFileFormat.ScalingFilter; Graphics.ScalingFilter.Value = configurationFileFormat.ScalingFilter;
@@ -12,6 +12,7 @@ namespace Ryujinx.UI.Common.Helper
public static bool? OverrideDockedMode { get; private set; } public static bool? OverrideDockedMode { get; private set; }
public static bool? OverrideHardwareAcceleration { get; private set; } public static bool? OverrideHardwareAcceleration { get; private set; }
public static string OverrideGraphicsBackend { get; private set; } public static string OverrideGraphicsBackend { get; private set; }
public static string OverrideTranslationLayer { get; private set; }
public static string OverrideBackendThreading { get; private set; } public static string OverrideBackendThreading { get; private set; }
public static string OverrideHideCursor { get; private set; } public static string OverrideHideCursor { get; private set; }
public static string BaseDirPathArg { get; private set; } public static string BaseDirPathArg { get; private set; }
@@ -109,6 +110,16 @@ namespace Ryujinx.UI.Common.Helper
OverrideGraphicsBackend = args[++i]; OverrideGraphicsBackend = args[++i];
break; break;
case "--translation-layer":
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
OverrideTranslationLayer = args[++i];
break;
case "--backend-threading": case "--backend-threading":
if (i + 1 >= args.Length) if (i + 1 >= args.Length)
{ {
+9 -4
View File
@@ -43,7 +43,6 @@ using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common; using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration; using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper; using Ryujinx.UI.Common.Helper;
using Silk.NET.Vulkan;
using SkiaSharp; using SkiaSharp;
using SPB.Graphics.Exceptions; using SPB.Graphics.Exceptions;
using SPB.Graphics.Vulkan; using SPB.Graphics.Vulkan;
@@ -939,10 +938,11 @@ namespace Ryujinx.Ava
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan) if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan)
{ {
renderer = new VulkanRenderer( renderer = new VulkanRenderer(
Vk.GetApi(), VulkanSpbApi.GetApiFromSpb(),
((EmbeddedWindowVulkan)RendererHost.EmbeddedWindow).CreateSurface, ((EmbeddedWindowVulkan)RendererHost.EmbeddedWindow).CreateSurface,
VulkanHelper.GetRequiredInstanceExtensions, VulkanHelper.GetRequiredInstanceExtensions,
ConfigurationState.Instance.Graphics.PreferredGpu.Value); ConfigurationState.Instance.Graphics.PreferredGpu.Value,
ConfigurationState.Instance.Graphics.TranslationLayer.Value);
} }
else else
{ {
@@ -1183,7 +1183,12 @@ namespace Ryujinx.Ava
{ {
_viewModel.BackendText = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch _viewModel.BackendText = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
{ {
GraphicsBackend.Vulkan => "Vulkan", GraphicsBackend.Vulkan when !OperatingSystem.IsMacOS() => "Vulkan",
GraphicsBackend.Vulkan when Environment.GetEnvironmentVariable("VK_DRIVER_FILES")!.Contains("MoltenVK")
=> "MoltenVK",
GraphicsBackend.Vulkan when
Environment.GetEnvironmentVariable("VK_DRIVER_FILES")!.Contains("kosmickrisp") => "KosmicKrisp",
GraphicsBackend.Vulkan => _viewModel.BackendText,
GraphicsBackend.OpenGl => "OpenGL", GraphicsBackend.OpenGl => "OpenGL",
_ => throw new NotImplementedException() _ => throw new NotImplementedException()
}; };
+2
View File
@@ -189,6 +189,8 @@
"SettingsTabSystemIgnoreControllerApplet": "Ignore Controller Applet", "SettingsTabSystemIgnoreControllerApplet": "Ignore Controller Applet",
"SettingsTabGraphics": "Graphics", "SettingsTabGraphics": "Graphics",
"SettingsTabGraphicsAPI": "Graphics API", "SettingsTabGraphicsAPI": "Graphics API",
"SettingsTabTranslationLayer": "Translation Layer (Vulkan):",
"SettingsTabTranslationLayerTooltip": "MoltenVK is a Vulkan Portability implementation, enabling Vulkan applications to run on macOS.\n\nKosmicKrisp is a Vulkan (1.3) conformant Vulkan-on-Metal driver and the eventual successor to MoltenVK.\n\nKosmicKrisp is not yet feature-complete, meaning that games *may* not render correctly or possibly even crash.\n\nUse MoltenVK if unsure.",
"SettingsTabGraphicsEnableShaderCache": "Enable Shader Cache", "SettingsTabGraphicsEnableShaderCache": "Enable Shader Cache",
"SettingsTabGraphicsAnisotropicFiltering": "Anisotropic Filtering:", "SettingsTabGraphicsAnisotropicFiltering": "Anisotropic Filtering:",
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto", "SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
+3 -2
View File
@@ -289,7 +289,7 @@ namespace Ryujinx.Headless
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow) if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
{ {
string preferredGpuId = string.Empty; string preferredGpuId = string.Empty;
Vk api = Vk.GetApi(); Vk api = VulkanSpbApi.GetApiFromSpb();
if (!string.IsNullOrEmpty(options.PreferredGPUVendor)) if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{ {
@@ -310,7 +310,8 @@ namespace Ryujinx.Headless
api, api,
(instance, _) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))), (instance, _) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
VulkanWindow.GetRequiredInstanceExtensions, VulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId); preferredGpuId,
options.TranslationLayer);
} }
return new OpenGLRenderer(); return new OpenGLRenderer();
-6
View File
@@ -12,7 +12,6 @@ using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
@@ -74,11 +73,6 @@ namespace Ryujinx.Headless
}; };
} }
if (OperatingSystem.IsMacOS())
{
MVKInitialization.InitializeResolver();
}
Parser.Default.ParseArguments<Options>(args) Parser.Default.ParseArguments<Options>(args)
.WithParsed(options => Load(args, options)) .WithParsed(options => Load(args, options))
.WithNotParsed(errors => errors.Output()); .WithNotParsed(errors => errors.Output());
+7 -1
View File
@@ -131,7 +131,10 @@ namespace Ryujinx.Headless
if (NeedsOverride(nameof(GraphicsBackend))) if (NeedsOverride(nameof(GraphicsBackend)))
GraphicsBackend = configurationState.Graphics.GraphicsBackend; GraphicsBackend = configurationState.Graphics.GraphicsBackend;
if (NeedsOverride(nameof(TranslationLayer)))
TranslationLayer = configurationState.Graphics.TranslationLayer;
if (NeedsOverride(nameof(AntiAliasing))) if (NeedsOverride(nameof(AntiAliasing)))
AntiAliasing = configurationState.Graphics.AntiAliasing; AntiAliasing = configurationState.Graphics.AntiAliasing;
@@ -370,6 +373,9 @@ namespace Ryujinx.Headless
[Option("graphics-backend", Required = false, Default = GraphicsBackend.Vulkan, HelpText = "Change Graphics Backend to use.")] [Option("graphics-backend", Required = false, Default = GraphicsBackend.Vulkan, HelpText = "Change Graphics Backend to use.")]
public GraphicsBackend GraphicsBackend { get; set; } public GraphicsBackend GraphicsBackend { get; set; }
[Option("translation-layer", Required = false, Default = TranslationLayer.MoltenVK, HelpText = "Change Translation Layer to use.")]
public TranslationLayer TranslationLayer { get; set; }
[Option("preferred-gpu-vendor", Required = false, Default = "", HelpText = "When using the Vulkan backend, prefer using the GPU from the specified vendor.")] [Option("preferred-gpu-vendor", Required = false, Default = "", HelpText = "When using the Vulkan backend, prefer using the GPU from the specified vendor.")]
public string PreferredGPUVendor { get; set; } public string PreferredGPUVendor { get; set; }
+23 -18
View File
@@ -8,8 +8,6 @@ using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop; using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.Graphics.RenderDocApi;
using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless; using Ryujinx.Headless;
using Ryujinx.Modules; using Ryujinx.Modules;
using Ryujinx.SDL3.Common; using Ryujinx.SDL3.Common;
@@ -27,7 +25,6 @@ namespace Ryujinx.Ava
{ {
internal partial class Program internal partial class Program
{ {
//
public static double WindowScaleFactor { get; set; } public static double WindowScaleFactor { get; set; }
public static double DesktopScaleFactor { get; set; } = 1.0; public static double DesktopScaleFactor { get; set; } = 1.0;
public static string Version { get; private set; } public static string Version { get; private set; }
@@ -115,11 +112,6 @@ namespace Ryujinx.Ava
// Parse arguments // Parse arguments
CommandLineState.ParseArguments(args); CommandLineState.ParseArguments(args);
if (OperatingSystem.IsMacOS())
{
MVKInitialization.InitializeResolver();
}
// Delete backup files after updating. // Delete backup files after updating.
Task.Run(Updater.CleanupUpdate); Task.Run(Updater.CleanupUpdate);
@@ -219,19 +211,32 @@ namespace Ryujinx.Ava
UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration.Value; UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration.Value;
// Check if graphics backend was overridden // Change graphics backend from OpenGL to Vulkan on macOS
if (CommandLineState.OverrideGraphicsBackend != null) if (OperatingSystem.IsMacOS() && (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl))
{ {
if (CommandLineState.OverrideGraphicsBackend.ToLower() == "opengl") ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
{
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
}
else if (CommandLineState.OverrideGraphicsBackend.ToLower() == "vulkan")
{
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.Vulkan;
}
} }
// Check if graphics backend was overridden
if (CommandLineState.OverrideGraphicsBackend is not null)
{
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = CommandLineState.OverrideGraphicsBackend.ToLower() switch
{
"opengl" => GraphicsBackend.OpenGl,
"vulkan" => GraphicsBackend.Vulkan,
_ => ConfigurationState.Instance.Graphics.GraphicsBackend.Value
};
}
// Check if translation layer was overridden
if (CommandLineState.OverrideTranslationLayer is not null)
ConfigurationState.Instance.Graphics.TranslationLayer.Value = CommandLineState.OverrideTranslationLayer.ToLower() switch
{
"moltenvk" => TranslationLayer.MoltenVK,
"kosmickrisp" => TranslationLayer.KosmicKrisp,
_ => ConfigurationState.Instance.Graphics.TranslationLayer.Value
};
// Check if backend threading was overridden // Check if backend threading was overridden
if (CommandLineState.OverrideBackendThreading is not null) if (CommandLineState.OverrideBackendThreading is not null)
ConfigurationState.Instance.Graphics.BackendThreading.Value = CommandLineState.OverrideBackendThreading.ToLower() switch ConfigurationState.Instance.Graphics.BackendThreading.Value = CommandLineState.OverrideBackendThreading.ToLower() switch
+16 -1
View File
@@ -47,11 +47,12 @@
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Condition="'$(RuntimeIdentifier)' == 'win-x64' OR '$(RuntimeIdentifier)' == 'win-arm64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Condition="'$(RuntimeIdentifier)' == 'win-x64' OR '$(RuntimeIdentifier)' == 'win-arm64'" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.KosmicKrisp" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64' AND '$(RuntimeIdentifier)' != 'win-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.SPB" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.MoltenVK" Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'" /> <PackageReference Include="Ryujinx.Graphics.Vulkan.MoltenVK" Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64'" />
<PackageReference Include="Silk.NET.Vulkan" /> <PackageReference Include="Silk.NET.Vulkan" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" /> <PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" /> <PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
<PackageReference Include="SPB" />
<PackageReference Include="SharpZipLib" /> <PackageReference Include="SharpZipLib" />
</ItemGroup> </ItemGroup>
@@ -90,6 +91,20 @@
</Content> </Content>
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'osx-arm64' OR '$(RuntimeIdentifier)' == 'osx-x64'">
<Content Include="..\..\distribution\macos\vulkan\icd.d\MoltenVK_icd-flat.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>MoltenVK_icd.json</TargetPath>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'osx-arm64'">
<Content Include="..\..\distribution\macos\vulkan\icd.d\libkosmickrisp_icd-flat.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>libkosmickrisp_icd.json</TargetPath>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64'" > <ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64'" >
<Content Include="..\..\distribution\linux\Ryujinx.sh"> <Content Include="..\..\distribution\linux\Ryujinx.sh">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+15 -1
View File
@@ -118,6 +118,8 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsHypervisorAvailable => OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64; public bool IsHypervisorAvailable => OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
public bool IsKosmicKrispAvailable => OperatingSystem.IsMacOSVersionAtLeast(15);
public bool GameDirectoryChanged public bool GameDirectoryChanged
{ {
get => _gameDirectoryChanged; get => _gameDirectoryChanged;
@@ -317,12 +319,22 @@ namespace Ryujinx.Ava.UI.ViewModels
get; get;
set set
{ {
field = value; field = IsMacOS ? 0 : value;
OnPropertyChanged(); OnPropertyChanged();
OnPropertyChanged(nameof(IsVulkanSelected)); OnPropertyChanged(nameof(IsVulkanSelected));
} }
} }
public int TranslationLayerIndex
{
get;
set
{
field = value;
OnPropertyChanged();
}
}
public int ScalingFilter public int ScalingFilter
{ {
get => _scalingFilter; get => _scalingFilter;
@@ -626,6 +638,7 @@ namespace Ryujinx.Ava.UI.ViewModels
// Graphics // Graphics
GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value; GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value;
TranslationLayerIndex = (int)config.Graphics.TranslationLayer.Value;
// Physical devices are queried asynchronously hence the preferred index config value is loaded in LoadAvailableGpus(). // Physical devices are queried asynchronously hence the preferred index config value is loaded in LoadAvailableGpus().
EnableShaderCache = config.Graphics.EnableShaderCache; EnableShaderCache = config.Graphics.EnableShaderCache;
EnableTextureRecompression = config.Graphics.EnableTextureRecompression; EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
@@ -746,6 +759,7 @@ namespace Ryujinx.Ava.UI.ViewModels
// Graphics // Graphics
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex; config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
config.Graphics.TranslationLayer.Value = (TranslationLayer)TranslationLayerIndex;
config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex); config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex);
config.Graphics.EnableShaderCache.Value = EnableShaderCache; config.Graphics.EnableShaderCache.Value = EnableShaderCache;
config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression; config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
@@ -28,7 +28,7 @@
Spacing="10"> Spacing="10">
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" /> <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" />
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10"> <StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal" IsVisible="{Binding !IsMacOS}">
<TextBlock VerticalAlignment="Center" <TextBlock VerticalAlignment="Center"
ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}" ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}"
Text="{locale:Locale SettingsTabGraphicsBackend}" Text="{locale:Locale SettingsTabGraphicsBackend}"
@@ -45,6 +45,22 @@
Content="OpenGL" /> Content="OpenGL" />
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsMacOS}">
<TextBlock VerticalAlignment="Center"
ToolTip.Tip="{locale:Locale SettingsTabTranslationLayerTooltip}"
Text="{locale:Locale SettingsTabTranslationLayer}"
Width="250" />
<ComboBox Width="350"
HorizontalContentAlignment="Left"
ToolTip.Tip="{locale:Locale SettingsTabTranslationLayerTooltip}"
SelectedIndex="{Binding TranslationLayerIndex}">
<ComboBoxItem
Content="MoltenVK" />
<ComboBoxItem
IsEnabled="{Binding IsKosmicKrispAvailable}"
Content="KosmicKrisp" />
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}"> <StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}">
<TextBlock VerticalAlignment="Center" <TextBlock VerticalAlignment="Center"
ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}" ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}"
@@ -56,7 +72,24 @@
SelectedIndex="{Binding PreferredGpuIndex}" SelectedIndex="{Binding PreferredGpuIndex}"
ItemsSource="{Binding AvailableGpus}"/> ItemsSource="{Binding AvailableGpus}"/>
</StackPanel> </StackPanel>
</StackPanel> <StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center"
ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}"
Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}"
Width="250" />
<ComboBox Width="350"
HorizontalContentAlignment="Left"
ToolTip.Tip="{locale:Locale GalThreadingTooltip}"
SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}">
<ComboBoxItem
Content="{locale:Locale CommonAuto}" />
<ComboBoxItem
Content="{locale:Locale CommonOff}" />
<ComboBoxItem
Content="{locale:Locale CommonOn}" />
</ComboBox>
</StackPanel>
</StackPanel>
<Separator Height="1" /> <Separator Height="1" />
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" /> <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" />
<StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10"> <StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10">