diff --git a/Directory.Packages.props b/Directory.Packages.props
index 64867fc5b..62a642374 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -46,7 +46,6 @@
-
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 9e197e85f..9ed282d09 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -77,15 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Gene
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}"
- ProjectSection(ProjectDependencies) = postProject
- {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E} = {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}
- EndProjectSection
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal.SharpMetalExtensions", "src/Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj", "{81EA598C-DBA1-40B0-8DA4-4796B78F2037}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
@@ -95,6 +86,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -217,6 +210,10 @@ Global
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -249,16 +246,9 @@ Global
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
- {C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/Ryujinx.Common/Configuration/GraphicsBackend.cs b/src/Ryujinx.Common/Configuration/GraphicsBackend.cs
index 9d399d560..e3b4f91b0 100644
--- a/src/Ryujinx.Common/Configuration/GraphicsBackend.cs
+++ b/src/Ryujinx.Common/Configuration/GraphicsBackend.cs
@@ -6,9 +6,7 @@ namespace Ryujinx.Common.Configuration
[JsonConverter(typeof(TypedStringEnumConverter))]
public enum GraphicsBackend
{
- Auto,
Vulkan,
OpenGl,
- Metal
}
}
diff --git a/src/Ryujinx.Common/TitleIDs.cs b/src/Ryujinx.Common/TitleIDs.cs
index 1bf788c96..82be1572f 100644
--- a/src/Ryujinx.Common/TitleIDs.cs
+++ b/src/Ryujinx.Common/TitleIDs.cs
@@ -10,54 +10,6 @@ namespace Ryujinx.Common
{
public static ReactiveObject> CurrentApplication { get; } = new();
- public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
- {
- switch (currentBackend)
- {
- case GraphicsBackend.Metal when !OperatingSystem.IsMacOS():
- case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS():
- return GraphicsBackend.Vulkan;
- case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal:
- return currentBackend;
- }
-
- if (!RunningPlatform.IsArmMac)
- return GraphicsBackend.Vulkan;
-
- return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
- }
-
- public static readonly string[] GreatMetalTitles =
- [
- "01009b500007c000", // ARMS
- "0100a5c00d162000", // Cuphead
- "010023800d64a000", // Deltarune
- "01003a30012c0000", // LEGO City Undercover
- "010048701995e000", // Luigi's Manion 2 HD
- "010028600EBDA000", // Mario 3D World
- "0100152000022000", // Mario Kart 8 Deluxe
- "010075a016a3a000", // Persona 4 Arena Ultimax
- "0100187003A36000", // Pokémon: Let's Go, Eevee!
- "010003f003a34000", // Pokémon: Let's Go, Pikachu!
- "01008C0016544000", // Sea of Stars
- "01006A800016E000", // Smash Ultimate
- "01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
-
- // These ones have small issues, but those happen on Vulkan as well:
- "01006f8002326000", // Animal Crossings: New Horizons
- "01009bf0072d4000", // Captain Toad: Treasure Tracker
- "01009510001ca000", // Fast RMX
- "01005CA01580E000", // Persona 5 Royal
- "0100b880154fc000", // Persona 5 The Royal (Japan)
- "010015100b514000", // Super Mario Bros. Wonder
- "0100000000010000", // Super Mario Odyssey
-
- // Further testing is appreciated, I did not test the entire game:
- //"010076f0049a2000", // Bayonetta
- //"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
- //"0100f4300bf2c000", // New Pokemon Snap
- ];
-
public static string GetDiscordGameAsset(string titleId)
=> DiscordGameAssetKeys.Contains(titleId) ? titleId : "game";
diff --git a/src/Ryujinx.Graphics.GAL/ComputeSize.cs b/src/Ryujinx.Graphics.GAL/ComputeSize.cs
deleted file mode 100644
index c8d89c0fe..000000000
--- a/src/Ryujinx.Graphics.GAL/ComputeSize.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Ryujinx.Graphics.GAL
-{
- public readonly struct ComputeSize
- {
- public readonly static ComputeSize VtgAsCompute = new(32, 32, 1);
-
- public readonly int X;
- public readonly int Y;
- public readonly int Z;
-
- public ComputeSize(int x, int y, int z)
- {
- X = x;
- Y = y;
- Z = z;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.GAL/Format.cs b/src/Ryujinx.Graphics.GAL/Format.cs
index b1eb68f72..17c42d2d4 100644
--- a/src/Ryujinx.Graphics.GAL/Format.cs
+++ b/src/Ryujinx.Graphics.GAL/Format.cs
@@ -339,84 +339,6 @@ namespace Ryujinx.Graphics.GAL
return 1;
}
- ///
- /// Get bytes per element for this format.
- ///
- /// Texture format
- /// Byte size for an element of this format (pixel, vertex attribute, etc)
- public static int GetBytesPerElement(this Format format)
- {
- int scalarSize = format.GetScalarSize();
-
- switch (format)
- {
- case Format.R8G8Unorm:
- case Format.R8G8Snorm:
- case Format.R8G8Uint:
- case Format.R8G8Sint:
- case Format.R8G8Uscaled:
- case Format.R8G8Sscaled:
- case Format.R16G16Float:
- case Format.R16G16Unorm:
- case Format.R16G16Snorm:
- case Format.R16G16Uint:
- case Format.R16G16Sint:
- case Format.R16G16Uscaled:
- case Format.R16G16Sscaled:
- case Format.R32G32Float:
- case Format.R32G32Uint:
- case Format.R32G32Sint:
- case Format.R32G32Uscaled:
- case Format.R32G32Sscaled:
- return 2 * scalarSize;
-
- case Format.R8G8B8Unorm:
- case Format.R8G8B8Snorm:
- case Format.R8G8B8Uint:
- case Format.R8G8B8Sint:
- case Format.R8G8B8Uscaled:
- case Format.R8G8B8Sscaled:
- case Format.R16G16B16Float:
- case Format.R16G16B16Unorm:
- case Format.R16G16B16Snorm:
- case Format.R16G16B16Uint:
- case Format.R16G16B16Sint:
- case Format.R16G16B16Uscaled:
- case Format.R16G16B16Sscaled:
- case Format.R32G32B32Float:
- case Format.R32G32B32Uint:
- case Format.R32G32B32Sint:
- case Format.R32G32B32Uscaled:
- case Format.R32G32B32Sscaled:
- return 3 * scalarSize;
-
- case Format.R8G8B8A8Unorm:
- case Format.R8G8B8A8Snorm:
- case Format.R8G8B8A8Uint:
- case Format.R8G8B8A8Sint:
- case Format.R8G8B8A8Srgb:
- case Format.R8G8B8A8Uscaled:
- case Format.R8G8B8A8Sscaled:
- case Format.B8G8R8A8Unorm:
- case Format.B8G8R8A8Srgb:
- case Format.R16G16B16A16Float:
- case Format.R16G16B16A16Unorm:
- case Format.R16G16B16A16Snorm:
- case Format.R16G16B16A16Uint:
- case Format.R16G16B16A16Sint:
- case Format.R16G16B16A16Uscaled:
- case Format.R16G16B16A16Sscaled:
- case Format.R32G32B32A32Float:
- case Format.R32G32B32A32Uint:
- case Format.R32G32B32A32Sint:
- case Format.R32G32B32A32Uscaled:
- case Format.R32G32B32A32Sscaled:
- return 4 * scalarSize;
- }
-
- return scalarSize;
- }
-
///
/// Checks if the texture format is a depth or depth-stencil format.
///
diff --git a/src/Ryujinx.Graphics.GAL/ShaderInfo.cs b/src/Ryujinx.Graphics.GAL/ShaderInfo.cs
index c7965a03d..2fd3227dc 100644
--- a/src/Ryujinx.Graphics.GAL/ShaderInfo.cs
+++ b/src/Ryujinx.Graphics.GAL/ShaderInfo.cs
@@ -4,22 +4,23 @@ namespace Ryujinx.Graphics.GAL
{
public int FragmentOutputMap { get; }
public ResourceLayout ResourceLayout { get; }
- public ComputeSize ComputeLocalSize { get; }
public ProgramPipelineState? State { get; }
public bool FromCache { get; set; }
- public ShaderInfo(
- int fragmentOutputMap,
- ResourceLayout resourceLayout,
- ComputeSize computeLocalSize,
- ProgramPipelineState? state,
- bool fromCache = false)
+ public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, ProgramPipelineState state, bool fromCache = false)
{
FragmentOutputMap = fragmentOutputMap;
ResourceLayout = resourceLayout;
- ComputeLocalSize = computeLocalSize;
State = state;
FromCache = fromCache;
}
+
+ public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, bool fromCache = false)
+ {
+ FragmentOutputMap = fragmentOutputMap;
+ ResourceLayout = resourceLayout;
+ State = null;
+ FromCache = fromCache;
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs
index 15f1a4a33..eba1b6030 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs
@@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
///
class VtgAsComputeContext : IDisposable
{
+ private const int DummyBufferSize = 16;
+
private readonly GpuContext _context;
///
@@ -46,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
1,
1,
1,
- format.GetBytesPerElement(),
+ 1,
format,
DepthStencilMode.Depth,
Target.TextureBuffer,
@@ -519,6 +521,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
return new BufferRange(_geometryIndexDataBuffer.Handle, offset, size, write);
}
+ ///
+ /// Gets the range for a dummy 16 bytes buffer, filled with zeros.
+ ///
+ /// Dummy buffer range
+ public BufferRange GetDummyBufferRange()
+ {
+ if (_dummyBuffer == BufferHandle.Null)
+ {
+ _dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize, BufferAccess.DeviceMemory);
+ _context.Renderer.Pipeline.ClearBuffer(_dummyBuffer, 0, DummyBufferSize, 0);
+ }
+
+ return new BufferRange(_dummyBuffer, 0, DummyBufferSize);
+ }
+
///
/// Gets the range for a sequential index buffer, with ever incrementing index values.
///
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
index 16a19debe..0d59275ff 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
@@ -147,6 +147,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
{
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
+ SetDummyBufferTexture(_vertexAsCompute.Reservations, index, format);
continue;
}
@@ -162,12 +163,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
{
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
+ SetDummyBufferTexture(_vertexAsCompute.Reservations, index, format);
continue;
}
int vbStride = vertexBuffer.UnpackStride();
ulong vbSize = GetVertexBufferSize(address, endAddress.Pack(), vbStride, _indexed, instanced, _firstVertex, _count);
+ ulong oldVbSize = vbSize;
+
ulong attributeOffset = (ulong)vertexAttrib.UnpackOffset();
int componentSize = format.GetScalarSize();
@@ -340,6 +344,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
return maxOutputVertices / verticesPerPrimitive;
}
+ ///
+ /// Binds a dummy buffer as vertex buffer into a buffer texture.
+ ///
+ /// Shader resource binding reservations
+ /// Buffer texture index
+ /// Buffer texture format
+ private readonly void SetDummyBufferTexture(ResourceReservations reservations, int index, Format format)
+ {
+ ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format);
+ bufferTexture.SetStorage(_vacContext.GetDummyBufferRange());
+
+ _context.Renderer.Pipeline.SetTextureAndSampler(ShaderStage.Compute, reservations.GetVertexBufferTextureBinding(index), bufferTexture, null);
+ }
+
///
/// Binds a vertex buffer into a buffer texture.
///
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index 4ef0caced..22ffe4812 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -324,11 +324,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
bool loadHostCache = header.CodeGenVersion == CodeGenVersion;
- if (context.Capabilities.Api == TargetApi.Metal)
- {
- loadHostCache = false;
- }
-
int programIndex = 0;
DataEntry entry = new();
@@ -397,8 +392,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
context,
shaders,
specState.PipelineState,
- specState.TransformFeedbackDescriptors != null,
- specState.ComputeState.GetLocalSize());
+ specState.TransformFeedbackDescriptors != null);
IProgram hostProgram;
@@ -635,10 +629,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
return;
}
- if (context.Capabilities.Api != TargetApi.Metal)
- {
- WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
- }
+ WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
}
///
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
index f8cb6c56b..a0d3e8c15 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
@@ -367,9 +366,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
try
{
- if (_context.Capabilities.Api == TargetApi.Metal && _context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
- Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]);
-
AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute);
_asyncTranslationQueue.Add(asyncTranslation, _cancellationToken);
}
@@ -494,12 +490,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
- ref GpuChannelComputeState computeState = ref compilation.SpecializationState.ComputeState;
-
- ShaderInfoBuilder shaderInfoBuilder = new(
- _context,
- compilation.SpecializationState.TransformFeedbackDescriptors != null,
- computeLocalSize: computeState.GetLocalSize());
+ ShaderInfoBuilder shaderInfoBuilder = new(_context, compilation.SpecializationState.TransformFeedbackDescriptors != null);
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
{
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
index c7d86a47e..393584bd4 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
@@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly GpuAccessorState _state;
private readonly int _stageIndex;
private readonly bool _compute;
- private readonly bool _isOpenGL;
+ private readonly bool _isVulkan;
private readonly bool _hasGeometryShader;
private readonly bool _supportsQuads;
@@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_channel = channel;
_state = state;
_stageIndex = stageIndex;
- _isOpenGL = context.Capabilities.Api == TargetApi.OpenGL;
+ _isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
_hasGeometryShader = hasGeometryShader;
_supportsQuads = context.Capabilities.SupportsQuads;
@@ -117,10 +117,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
public GpuGraphicsState QueryGraphicsState()
{
return _state.GraphicsState.CreateShaderGraphicsState(
- _isOpenGL,
+ !_isVulkan,
_supportsQuads,
_hasGeometryShader,
- !_isOpenGL || _state.GraphicsState.YNegateEnabled);
+ _isVulkan || _state.GraphicsState.YNegateEnabled);
}
///
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
index 701ff764a..d89eebabf 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
@@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
- if (_context.Capabilities.Api != TargetApi.OpenGL)
+ if (_context.Capabilities.Api == TargetApi.Vulkan)
{
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
}
@@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
- if (_context.Capabilities.Api != TargetApi.OpenGL)
+ if (_context.Capabilities.Api == TargetApi.Vulkan)
{
if (count == 1)
{
@@ -103,7 +103,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
- if (_context.Capabilities.Api != TargetApi.OpenGL)
+ if (_context.Capabilities.Api == TargetApi.Vulkan)
{
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
}
@@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
- if (_context.Capabilities.Api != TargetApi.OpenGL)
+ if (_context.Capabilities.Api == TargetApi.Vulkan)
{
if (count == 1)
{
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs
index 720f7e796..d8cdbc348 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs
@@ -1,5 +1,3 @@
-using Ryujinx.Graphics.GAL;
-
namespace Ryujinx.Graphics.Gpu.Shader
{
///
@@ -63,14 +61,5 @@ namespace Ryujinx.Graphics.Gpu.Shader
SharedMemorySize = sharedMemorySize;
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
}
-
- ///
- /// Gets the local group size of the shader in a GAL compatible struct.
- ///
- /// Local group size
- public ComputeSize GetLocalSize()
- {
- return new ComputeSize(LocalSizeX, LocalSizeY, LocalSizeZ);
- }
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 476ae3d82..4fc66c4c0 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -117,7 +117,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private static string GetDiskCachePath()
{
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
- ? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader")
+ ? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
: null;
}
@@ -204,7 +204,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
GpuChannelComputeState computeState,
ulong gpuVa)
{
- if (_cpPrograms.TryGetValue(gpuVa, out CachedShaderProgram cpShader) && IsShaderEqual(channel, poolState, computeState, cpShader, gpuVa))
+ if (_cpPrograms.TryGetValue(gpuVa, out var cpShader) && IsShaderEqual(channel, poolState, computeState, cpShader, gpuVa))
{
return cpShader;
}
@@ -223,11 +223,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
TranslatorContext translatorContext = DecodeComputeShader(gpuAccessor, _context.Capabilities.Api, gpuVa);
TranslatedShader translatedShader = TranslateShader(_dumper, channel, translatorContext, cachedGuestCode, asCompute: false);
- ShaderSource[] shaderSourcesArray = [CreateShaderSource(translatedShader.Program)];
- ShaderInfo info = ShaderInfoBuilder.BuildForCompute(
- _context,
- translatedShader.Program.Info,
- computeState.GetLocalSize());
+ ShaderSource[] shaderSourcesArray = new ShaderSource[] { CreateShaderSource(translatedShader.Program) };
+ ShaderInfo info = ShaderInfoBuilder.BuildForCompute(_context, translatedShader.Program.Info);
IProgram hostProgram = _context.Renderer.CreateProgram(shaderSourcesArray, info);
cpShader = new CachedShaderProgram(hostProgram, specState, translatedShader.Shader);
@@ -254,8 +251,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
channel.TextureManager.UpdateRenderTargets();
- RtControl rtControl = state.RtControl;
- TextureMsaaMode msaaMode = state.RtMsaaMode;
+ var rtControl = state.RtControl;
+ var msaaMode = state.RtMsaaMode;
pipeline.SamplesCount = msaaMode.SamplesInX() * msaaMode.SamplesInY();
@@ -265,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int rtIndex = rtControl.UnpackPermutationIndex(index);
- RtColorState colorState = state.RtColorState[rtIndex];
+ var colorState = state.RtColorState[rtIndex];
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
{
@@ -310,12 +307,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
ref GpuChannelGraphicsState graphicsState,
ShaderAddresses addresses)
{
- if (_gpPrograms.TryGetValue(addresses, out CachedShaderProgram gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses))
+ if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses))
{
return gpShaders;
}
- if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out CachedGraphicsGuestCode cachedGuestCode))
+ if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out var cachedGuestCode))
{
_gpPrograms[addresses] = gpShaders;
return gpShaders;
@@ -368,7 +365,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
bool geometryToCompute = ShouldConvertGeometryToCompute(_context, geometryHasStore);
CachedShaderStage[] shaders = new CachedShaderStage[Constants.ShaderStages + 1];
- List shaderSources = [];
+ List shaderSources = new();
TranslatorContext previousStage = null;
ShaderInfoBuilder infoBuilder = new(_context, transformFeedbackDescriptors != null, vertexToCompute);
@@ -428,8 +425,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
TranslatorContext lastInVertexPipeline = geometryToCompute ? translatorContexts[4] ?? currentStage : currentStage;
- (program, ShaderProgramInfo vacInfo) = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
- infoBuilder.AddStageInfoVac(vacInfo);
+ program = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
}
else
{
@@ -534,9 +530,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
private ShaderAsCompute CreateHostVertexAsComputeProgram(ShaderProgram program, TranslatorContext context, bool tfEnabled)
{
ShaderSource source = new(program.Code, program.BinaryCode, ShaderStage.Compute, program.Language);
- ShaderInfo info = ShaderInfoBuilder.BuildForVertexAsCompute(_context, program.Info, context.GetVertexAsComputeInfo(), tfEnabled);
+ ShaderInfo info = ShaderInfoBuilder.BuildForVertexAsCompute(_context, program.Info, tfEnabled);
- return new(_context.Renderer.CreateProgram([source], info), program.Info, context.GetResourceReservations());
+ return new(_context.Renderer.CreateProgram(new[] { source }, info), program.Info, context.GetResourceReservations());
}
///
@@ -586,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
{
- TfState tf = state.TfState[i];
+ var tf = state.TfState[i];
descs[i] = new TransformFeedbackDescriptor(
tf.BufferIndex,
@@ -692,7 +688,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// The generated translator context
public static TranslatorContext DecodeComputeShader(IGpuAccessor gpuAccessor, TargetApi api, ulong gpuVa)
{
- TranslationOptions options = CreateTranslationOptions(api, DefaultFlags | TranslationFlags.Compute);
+ var options = CreateTranslationOptions(api, DefaultFlags | TranslationFlags.Compute);
return Translator.CreateContext(gpuVa, gpuAccessor, options);
}
@@ -709,7 +705,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// The generated translator context
public static TranslatorContext DecodeGraphicsShader(IGpuAccessor gpuAccessor, TargetApi api, TranslationFlags flags, ulong gpuVa)
{
- TranslationOptions options = CreateTranslationOptions(api, flags);
+ var options = CreateTranslationOptions(api, flags);
return Translator.CreateContext(gpuVa, gpuAccessor, options);
}
@@ -735,7 +731,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
ulong cb1DataAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(0, 1);
- MemoryManager memoryManager = channel.MemoryManager;
+ var memoryManager = channel.MemoryManager;
codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray();
codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
@@ -773,7 +769,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Compiled graphics shader code
private static TranslatedShader TranslateShader(ShaderDumper dumper, GpuChannel channel, TranslatorContext context, byte[] code, bool asCompute)
{
- MemoryManager memoryManager = channel.MemoryManager;
+ var memoryManager = channel.MemoryManager;
ulong cb1DataAddress = context.Stage == ShaderStage.Compute
? channel.BufferManager.GetComputeUniformBufferAddress(1)
@@ -801,7 +797,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
if (address == MemoryManager.PteUnmapped || size == 0)
{
- return [];
+ return Array.Empty();
}
return memoryManager.Physical.GetSpan(address, size).ToArray();
@@ -826,20 +822,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// Creates shader translation options with the requested graphics API and flags.
- /// The shader language is chosen based on the current configuration and graphics API.
+ /// The shader language is choosen based on the current configuration and graphics API.
///
/// Target graphics API
/// Translation flags
/// Translation options
private static TranslationOptions CreateTranslationOptions(TargetApi api, TranslationFlags flags)
{
- TargetLanguage lang = api switch
- {
- TargetApi.OpenGL => TargetLanguage.Glsl,
- TargetApi.Vulkan => GraphicsConfig.EnableSpirvCompilationOnVulkan ? TargetLanguage.Spirv : TargetLanguage.Glsl,
- TargetApi.Metal => TargetLanguage.Msl,
- _ => throw new NotImplementedException()
- };
+ TargetLanguage lang = GraphicsConfig.EnableSpirvCompilationOnVulkan && api == TargetApi.Vulkan
+ ? TargetLanguage.Spirv
+ : TargetLanguage.Glsl;
return new TranslationOptions(lang, api, flags);
}
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs
index 8aa48e0ce..c74c612a5 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs
@@ -22,7 +22,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
ResourceStages.Geometry;
private readonly GpuContext _context;
- private readonly ComputeSize _computeLocalSize;
private int _fragmentOutputMap;
@@ -40,11 +39,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// GPU context that owns the shaders that will be added to the builder
/// Indicates if the graphics shader is used with transform feedback enabled
/// Indicates that the vertex shader will be emulated on a compute shader
- /// Indicates the local thread size for a compute shader
- public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false, ComputeSize computeLocalSize = default)
+ public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false)
{
_context = context;
- _computeLocalSize = computeLocalSize;
_fragmentOutputMap = -1;
@@ -98,7 +95,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count, bool write = false)
{
AddDescriptor(stages, type, setIndex, start, count);
- // AddUsage(stages, type, setIndex, start, count, write);
+ AddUsage(stages, type, setIndex, start, count, write);
}
///
@@ -162,25 +159,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
AddUsage(info.Images, stages, isImage: true);
}
- public void AddStageInfoVac(ShaderProgramInfo info)
- {
- ResourceStages stages = info.Stage switch
- {
- ShaderStage.Compute => ResourceStages.Compute,
- ShaderStage.Vertex => ResourceStages.Vertex,
- ShaderStage.TessellationControl => ResourceStages.TessellationControl,
- ShaderStage.TessellationEvaluation => ResourceStages.TessellationEvaluation,
- ShaderStage.Geometry => ResourceStages.Geometry,
- ShaderStage.Fragment => ResourceStages.Fragment,
- _ => ResourceStages.None,
- };
-
- AddUsage(info.CBuffers, stages, isStorage: false);
- AddUsage(info.SBuffers, stages, isStorage: true);
- AddUsage(info.Textures, stages, isImage: false);
- AddUsage(info.Images, stages, isImage: true);
- }
-
///
/// Adds a resource descriptor to the list of descriptors.
///
@@ -383,7 +361,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
ResourceLayout resourceLayout = new(descriptors.AsReadOnly(), usages.AsReadOnly());
- return new ShaderInfo(_fragmentOutputMap, resourceLayout, _computeLocalSize, pipeline, fromCache);
+ if (pipeline.HasValue)
+ {
+ return new ShaderInfo(_fragmentOutputMap, resourceLayout, pipeline.Value, fromCache);
+ }
+ else
+ {
+ return new ShaderInfo(_fragmentOutputMap, resourceLayout, fromCache);
+ }
}
///
@@ -393,16 +378,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Shaders from the disk cache
/// Optional pipeline for background compilation
/// Indicates if the graphics shader is used with transform feedback enabled
- /// Compute local thread size
/// Shader information
public static ShaderInfo BuildForCache(
GpuContext context,
IEnumerable programs,
ProgramPipelineState? pipeline,
- bool tfEnabled,
- ComputeSize computeLocalSize)
+ bool tfEnabled)
{
- ShaderInfoBuilder builder = new(context, tfEnabled, computeLocalSize: computeLocalSize);
+ ShaderInfoBuilder builder = new(context, tfEnabled);
foreach (CachedShaderStage program in programs)
{
@@ -420,12 +403,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// GPU context that owns the shader
/// Compute shader information
- /// Compute local thread size
/// True if the compute shader comes from a disk cache, false otherwise
/// Shader information
- public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, ComputeSize computeLocalSize, bool fromCache = false)
+ public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, bool fromCache = false)
{
- ShaderInfoBuilder builder = new(context, tfEnabled: false, vertexAsCompute: false, computeLocalSize: computeLocalSize);
+ ShaderInfoBuilder builder = new(context, tfEnabled: false, vertexAsCompute: false);
builder.AddStageInfo(info);
@@ -440,11 +422,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Indicates if the graphics shader is used with transform feedback enabled
/// True if the compute shader comes from a disk cache, false otherwise
/// Shader information
- public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, ShaderProgramInfo info2, bool tfEnabled, bool fromCache = false)
+ public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, bool tfEnabled, bool fromCache = false)
{
- ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true, computeLocalSize: ComputeSize.VtgAsCompute);
+ ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true);
- builder.AddStageInfoVac(info2);
builder.AddStageInfo(info, vertexAsCompute: true);
return builder.Build(null, fromCache);
diff --git a/src/Ryujinx.Graphics.Metal/Auto.cs b/src/Ryujinx.Graphics.Metal/Auto.cs
deleted file mode 100644
index 7e79ecbc3..000000000
--- a/src/Ryujinx.Graphics.Metal/Auto.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Runtime.Versioning;
-using System.Threading;
-
-namespace Ryujinx.Graphics.Metal
-{
- interface IAuto
- {
- bool HasCommandBufferDependency(CommandBufferScoped cbs);
-
- void IncrementReferenceCount();
- void DecrementReferenceCount(int cbIndex);
- void DecrementReferenceCount();
- }
-
- interface IAutoPrivate : IAuto
- {
- void AddCommandBufferDependencies(CommandBufferScoped cbs);
- }
-
- [SupportedOSPlatform("macos")]
- class Auto : IAutoPrivate, IDisposable where T : IDisposable
- {
- private int _referenceCount;
- private T _value;
-
- private readonly BitMap _cbOwnership;
- private readonly MultiFenceHolder _waitable;
-
- private bool _disposed;
- private bool _destroyed;
-
- public Auto(T value)
- {
- _referenceCount = 1;
- _value = value;
- _cbOwnership = new BitMap(CommandBufferPool.MaxCommandBuffers);
- }
-
- public Auto(T value, MultiFenceHolder waitable) : this(value)
- {
- _waitable = waitable;
- }
-
- public T Get(CommandBufferScoped cbs, int offset, int size, bool write = false)
- {
- _waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size, write);
- return Get(cbs);
- }
-
- public T GetUnsafe()
- {
- return _value;
- }
-
- public T Get(CommandBufferScoped cbs)
- {
- if (!_destroyed)
- {
- AddCommandBufferDependencies(cbs);
- }
-
- return _value;
- }
-
- public bool HasCommandBufferDependency(CommandBufferScoped cbs)
- {
- return _cbOwnership.IsSet(cbs.CommandBufferIndex);
- }
-
- public bool HasRentedCommandBufferDependency(CommandBufferPool cbp)
- {
- return _cbOwnership.AnySet();
- }
-
- public void AddCommandBufferDependencies(CommandBufferScoped cbs)
- {
- // We don't want to add a reference to this object to the command buffer
- // more than once, so if we detect that the command buffer already has ownership
- // of this object, then we can just return without doing anything else.
- if (_cbOwnership.Set(cbs.CommandBufferIndex))
- {
- if (_waitable != null)
- {
- cbs.AddWaitable(_waitable);
- }
-
- cbs.AddDependant(this);
- }
- }
-
- public bool TryIncrementReferenceCount()
- {
- int lastValue;
- do
- {
- lastValue = _referenceCount;
-
- if (lastValue == 0)
- {
- return false;
- }
- }
- while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
-
- return true;
- }
-
- public void IncrementReferenceCount()
- {
- if (Interlocked.Increment(ref _referenceCount) == 1)
- {
- Interlocked.Decrement(ref _referenceCount);
- throw new InvalidOperationException("Attempted to increment the reference count of an object that was already destroyed.");
- }
- }
-
- public void DecrementReferenceCount(int cbIndex)
- {
- _cbOwnership.Clear(cbIndex);
- DecrementReferenceCount();
- }
-
- public void DecrementReferenceCount()
- {
- if (Interlocked.Decrement(ref _referenceCount) == 0)
- {
- _value.Dispose();
- _value = default;
- _destroyed = true;
- }
-
- Debug.Assert(_referenceCount >= 0);
- }
-
- public void Dispose()
- {
- if (!_disposed)
- {
- DecrementReferenceCount();
- _disposed = true;
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/BackgroundResources.cs b/src/Ryujinx.Graphics.Metal/BackgroundResources.cs
deleted file mode 100644
index e38b877a6..000000000
--- a/src/Ryujinx.Graphics.Metal/BackgroundResources.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Collections.Generic;
-using System.Runtime.Versioning;
-using System.Threading;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class BackgroundResource : IDisposable
- {
- private readonly MetalRenderer _renderer;
-
- private CommandBufferPool _pool;
- private PersistentFlushBuffer _flushBuffer;
-
- public BackgroundResource(MetalRenderer renderer)
- {
- _renderer = renderer;
- }
-
- public CommandBufferPool GetPool()
- {
- if (_pool == null)
- {
- MTLCommandQueue queue = _renderer.BackgroundQueue;
- _pool = new CommandBufferPool(queue, true);
- _pool.Initialize(null); // TODO: Proper encoder factory for background render/compute
- }
-
- return _pool;
- }
-
- public PersistentFlushBuffer GetFlushBuffer()
- {
- _flushBuffer ??= new PersistentFlushBuffer(_renderer);
-
- return _flushBuffer;
- }
-
- public void Dispose()
- {
- _pool?.Dispose();
- _flushBuffer?.Dispose();
- }
- }
-
- [SupportedOSPlatform("macos")]
- class BackgroundResources : IDisposable
- {
- private readonly MetalRenderer _renderer;
-
- private readonly Dictionary _resources;
-
- public BackgroundResources(MetalRenderer renderer)
- {
- _renderer = renderer;
-
- _resources = new Dictionary();
- }
-
- private void Cleanup()
- {
- lock (_resources)
- {
- foreach (KeyValuePair tuple in _resources)
- {
- if (!tuple.Key.IsAlive)
- {
- tuple.Value.Dispose();
- _resources.Remove(tuple.Key);
- }
- }
- }
- }
-
- public BackgroundResource Get()
- {
- Thread thread = Thread.CurrentThread;
-
- lock (_resources)
- {
- if (!_resources.TryGetValue(thread, out BackgroundResource resource))
- {
- Cleanup();
-
- resource = new BackgroundResource(_renderer);
-
- _resources[thread] = resource;
- }
-
- return resource;
- }
- }
-
- public void Dispose()
- {
- lock (_resources)
- {
- foreach (BackgroundResource resource in _resources.Values)
- {
- resource.Dispose();
- }
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/BitMap.cs b/src/Ryujinx.Graphics.Metal/BitMap.cs
deleted file mode 100644
index 4ddc438c1..000000000
--- a/src/Ryujinx.Graphics.Metal/BitMap.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-namespace Ryujinx.Graphics.Metal
-{
- readonly struct BitMap
- {
- public const int IntSize = 64;
-
- private const int IntShift = 6;
- private const int IntMask = IntSize - 1;
-
- private readonly long[] _masks;
-
- public BitMap(int count)
- {
- _masks = new long[(count + IntMask) / IntSize];
- }
-
- public bool AnySet()
- {
- for (int i = 0; i < _masks.Length; i++)
- {
- if (_masks[i] != 0)
- {
- return true;
- }
- }
-
- return false;
- }
-
- public bool IsSet(int bit)
- {
- int wordIndex = bit >> IntShift;
- int wordBit = bit & IntMask;
-
- long wordMask = 1L << wordBit;
-
- return (_masks[wordIndex] & wordMask) != 0;
- }
-
- public bool IsSet(int start, int end)
- {
- if (start == end)
- {
- return IsSet(start);
- }
-
- int startIndex = start >> IntShift;
- int startBit = start & IntMask;
- long startMask = -1L << startBit;
-
- int endIndex = end >> IntShift;
- int endBit = end & IntMask;
- long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
-
- if (startIndex == endIndex)
- {
- return (_masks[startIndex] & startMask & endMask) != 0;
- }
-
- if ((_masks[startIndex] & startMask) != 0)
- {
- return true;
- }
-
- for (int i = startIndex + 1; i < endIndex; i++)
- {
- if (_masks[i] != 0)
- {
- return true;
- }
- }
-
- if ((_masks[endIndex] & endMask) != 0)
- {
- return true;
- }
-
- return false;
- }
-
- public bool Set(int bit)
- {
- int wordIndex = bit >> IntShift;
- int wordBit = bit & IntMask;
-
- long wordMask = 1L << wordBit;
-
- if ((_masks[wordIndex] & wordMask) != 0)
- {
- return false;
- }
-
- _masks[wordIndex] |= wordMask;
-
- return true;
- }
-
- public void SetRange(int start, int end)
- {
- if (start == end)
- {
- Set(start);
- return;
- }
-
- int startIndex = start >> IntShift;
- int startBit = start & IntMask;
- long startMask = -1L << startBit;
-
- int endIndex = end >> IntShift;
- int endBit = end & IntMask;
- long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
-
- if (startIndex == endIndex)
- {
- _masks[startIndex] |= startMask & endMask;
- }
- else
- {
- _masks[startIndex] |= startMask;
-
- for (int i = startIndex + 1; i < endIndex; i++)
- {
- _masks[i] |= -1;
- }
-
- _masks[endIndex] |= endMask;
- }
- }
-
- public void Clear(int bit)
- {
- int wordIndex = bit >> IntShift;
- int wordBit = bit & IntMask;
-
- long wordMask = 1L << wordBit;
-
- _masks[wordIndex] &= ~wordMask;
- }
-
- public void Clear()
- {
- for (int i = 0; i < _masks.Length; i++)
- {
- _masks[i] = 0;
- }
- }
-
- public void ClearInt(int start, int end)
- {
- for (int i = start; i <= end; i++)
- {
- _masks[i] = 0;
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/BufferHolder.cs b/src/Ryujinx.Graphics.Metal/BufferHolder.cs
deleted file mode 100644
index 630571658..000000000
--- a/src/Ryujinx.Graphics.Metal/BufferHolder.cs
+++ /dev/null
@@ -1,385 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-using System.Threading;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class BufferHolder : IDisposable
- {
- private CacheByRange _cachedConvertedBuffers;
-
- public int Size { get; }
-
- private readonly IntPtr _map;
- private readonly MetalRenderer _renderer;
- private readonly Pipeline _pipeline;
-
- private readonly MultiFenceHolder _waitable;
- private readonly Auto _buffer;
-
- private readonly ReaderWriterLockSlim _flushLock;
- private FenceHolder _flushFence;
- private int _flushWaiting;
-
- public BufferHolder(MetalRenderer renderer, Pipeline pipeline, MTLBuffer buffer, int size)
- {
- _renderer = renderer;
- _pipeline = pipeline;
- _map = buffer.Contents;
- _waitable = new MultiFenceHolder(size);
- _buffer = new Auto(new(buffer), _waitable);
-
- _flushLock = new ReaderWriterLockSlim();
-
- Size = size;
- }
-
- public Auto GetBuffer()
- {
- return _buffer;
- }
-
- public Auto GetBuffer(bool isWrite)
- {
- if (isWrite)
- {
- SignalWrite(0, Size);
- }
-
- return _buffer;
- }
-
- public Auto GetBuffer(int offset, int size, bool isWrite)
- {
- if (isWrite)
- {
- SignalWrite(offset, size);
- }
-
- return _buffer;
- }
-
- public void SignalWrite(int offset, int size)
- {
- if (offset == 0 && size == Size)
- {
- _cachedConvertedBuffers.Clear();
- }
- else
- {
- _cachedConvertedBuffers.ClearRange(offset, size);
- }
- }
-
- private void ClearFlushFence()
- {
- // Assumes _flushLock is held as writer.
-
- if (_flushFence != null)
- {
- if (_flushWaiting == 0)
- {
- _flushFence.Put();
- }
-
- _flushFence = null;
- }
- }
-
- private void WaitForFlushFence()
- {
- if (_flushFence == null)
- {
- return;
- }
-
- // If storage has changed, make sure the fence has been reached so that the data is in place.
- _flushLock.ExitReadLock();
- _flushLock.EnterWriteLock();
-
- if (_flushFence != null)
- {
- FenceHolder fence = _flushFence;
- Interlocked.Increment(ref _flushWaiting);
-
- // Don't wait in the lock.
-
- _flushLock.ExitWriteLock();
-
- fence.Wait();
-
- _flushLock.EnterWriteLock();
-
- if (Interlocked.Decrement(ref _flushWaiting) == 0)
- {
- fence.Put();
- }
-
- _flushFence = null;
- }
-
- // Assumes the _flushLock is held as reader, returns in same state.
- _flushLock.ExitWriteLock();
- _flushLock.EnterReadLock();
- }
-
- public PinnedSpan GetData(int offset, int size)
- {
- _flushLock.EnterReadLock();
-
- WaitForFlushFence();
-
- Span result;
-
- if (_map != IntPtr.Zero)
- {
- result = GetDataStorage(offset, size);
-
- // Need to be careful here, the buffer can't be unmapped while the data is being used.
- _buffer.IncrementReferenceCount();
-
- _flushLock.ExitReadLock();
-
- return PinnedSpan.UnsafeFromSpan(result, _buffer.DecrementReferenceCount);
- }
-
- throw new InvalidOperationException("The buffer is not mapped");
- }
-
- public unsafe Span GetDataStorage(int offset, int size)
- {
- int mappingSize = Math.Min(size, Size - offset);
-
- if (_map != IntPtr.Zero)
- {
- return new Span((void*)(_map + offset), mappingSize);
- }
-
- throw new InvalidOperationException("The buffer is not mapped.");
- }
-
- public unsafe void SetData(int offset, ReadOnlySpan data, CommandBufferScoped? cbs = null, bool allowCbsWait = true)
- {
- int dataSize = Math.Min(data.Length, Size - offset);
- if (dataSize == 0)
- {
- return;
- }
-
- if (_map != IntPtr.Zero)
- {
- // If persistently mapped, set the data directly if the buffer is not currently in use.
- bool isRented = _buffer.HasRentedCommandBufferDependency(_renderer.CommandBufferPool);
-
- // If the buffer is rented, take a little more time and check if the use overlaps this handle.
- bool needsFlush = isRented && _waitable.IsBufferRangeInUse(offset, dataSize, false);
-
- if (!needsFlush)
- {
- WaitForFences(offset, dataSize);
-
- data[..dataSize].CopyTo(new Span((void*)(_map + offset), dataSize));
-
- SignalWrite(offset, dataSize);
-
- return;
- }
- }
-
- if (cbs != null &&
- cbs.Value.Encoders.CurrentEncoderType == EncoderType.Render &&
- !(_buffer.HasCommandBufferDependency(cbs.Value) &&
- _waitable.IsBufferRangeInUse(cbs.Value.CommandBufferIndex, offset, dataSize)))
- {
- // If the buffer hasn't been used on the command buffer yet, try to preload the data.
- // This avoids ending and beginning render passes on each buffer data upload.
-
- cbs = _pipeline.GetPreloadCommandBuffer();
- }
-
- if (allowCbsWait)
- {
- _renderer.BufferManager.StagingBuffer.PushData(_renderer.CommandBufferPool, cbs, this, offset, data);
- }
- else
- {
- bool rentCbs = cbs == null;
- if (rentCbs)
- {
- cbs = _renderer.CommandBufferPool.Rent();
- }
-
- if (!_renderer.BufferManager.StagingBuffer.TryPushData(cbs.Value, this, offset, data))
- {
- // Need to do a slow upload.
- BufferHolder srcHolder = _renderer.BufferManager.Create(dataSize);
- srcHolder.SetDataUnchecked(0, data);
-
- Auto srcBuffer = srcHolder.GetBuffer();
- Auto dstBuffer = this.GetBuffer(true);
-
- Copy(cbs.Value, srcBuffer, dstBuffer, 0, offset, dataSize);
-
- srcHolder.Dispose();
- }
-
- if (rentCbs)
- {
- cbs.Value.Dispose();
- }
- }
- }
-
- public unsafe void SetDataUnchecked(int offset, ReadOnlySpan data)
- {
- int dataSize = Math.Min(data.Length, Size - offset);
- if (dataSize == 0)
- {
- return;
- }
-
- if (_map != IntPtr.Zero)
- {
- data[..dataSize].CopyTo(new Span((void*)(_map + offset), dataSize));
- }
- }
-
- public void SetDataUnchecked(int offset, ReadOnlySpan data) where T : unmanaged
- {
- SetDataUnchecked(offset, MemoryMarshal.AsBytes(data));
- }
-
- public static void Copy(
- CommandBufferScoped cbs,
- Auto src,
- Auto dst,
- int srcOffset,
- int dstOffset,
- int size,
- bool registerSrcUsage = true)
- {
- MTLBuffer srcBuffer = registerSrcUsage ? src.Get(cbs, srcOffset, size).Value : src.GetUnsafe().Value;
- MTLBuffer dstbuffer = dst.Get(cbs, dstOffset, size, true).Value;
-
- cbs.Encoders.EnsureBlitEncoder().CopyFromBuffer(
- srcBuffer,
- (ulong)srcOffset,
- dstbuffer,
- (ulong)dstOffset,
- (ulong)size);
- }
-
- public void WaitForFences()
- {
- _waitable.WaitForFences();
- }
-
- public void WaitForFences(int offset, int size)
- {
- _waitable.WaitForFences(offset, size);
- }
-
- private bool BoundToRange(int offset, ref int size)
- {
- if (offset >= Size)
- {
- return false;
- }
-
- size = Math.Min(Size - offset, size);
-
- return true;
- }
-
- public Auto GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
- {
- if (!BoundToRange(offset, ref size))
- {
- return null;
- }
-
- I8ToI16CacheKey key = new(_renderer);
-
- if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out BufferHolder holder))
- {
- holder = _renderer.BufferManager.Create((size * 2 + 3) & ~3);
-
- _renderer.HelperShader.ConvertI8ToI16(cbs, this, holder, offset, size);
-
- key.SetBuffer(holder.GetBuffer());
-
- _cachedConvertedBuffers.Add(offset, size, key, holder);
- }
-
- return holder.GetBuffer();
- }
-
- public Auto GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize)
- {
- if (!BoundToRange(offset, ref size))
- {
- return null;
- }
-
- TopologyConversionCacheKey key = new(_renderer, pattern, indexSize);
-
- if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out BufferHolder holder))
- {
- // The destination index size is always I32.
-
- int indexCount = size / indexSize;
-
- int convertedCount = pattern.GetConvertedCount(indexCount);
-
- holder = _renderer.BufferManager.Create(convertedCount * 4);
-
- _renderer.HelperShader.ConvertIndexBuffer(cbs, this, holder, pattern, indexSize, offset, indexCount);
-
- key.SetBuffer(holder.GetBuffer());
-
- _cachedConvertedBuffers.Add(offset, size, key, holder);
- }
-
- return holder.GetBuffer();
- }
-
- public bool TryGetCachedConvertedBuffer(int offset, int size, ICacheKey key, out BufferHolder holder)
- {
- return _cachedConvertedBuffers.TryGetValue(offset, size, key, out holder);
- }
-
- public void AddCachedConvertedBuffer(int offset, int size, ICacheKey key, BufferHolder holder)
- {
- _cachedConvertedBuffers.Add(offset, size, key, holder);
- }
-
- public void AddCachedConvertedBufferDependency(int offset, int size, ICacheKey key, Dependency dependency)
- {
- _cachedConvertedBuffers.AddDependency(offset, size, key, dependency);
- }
-
- public void RemoveCachedConvertedBuffer(int offset, int size, ICacheKey key)
- {
- _cachedConvertedBuffers.Remove(offset, size, key);
- }
-
-
- public void Dispose()
- {
- _pipeline.FlushCommandsIfWeightExceeding(_buffer, (ulong)Size);
-
- _buffer.Dispose();
- _cachedConvertedBuffers.Dispose();
-
- _flushLock.EnterWriteLock();
-
- ClearFlushFence();
-
- _flushLock.ExitWriteLock();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/BufferManager.cs b/src/Ryujinx.Graphics.Metal/BufferManager.cs
deleted file mode 100644
index 73a8d6fe7..000000000
--- a/src/Ryujinx.Graphics.Metal/BufferManager.cs
+++ /dev/null
@@ -1,237 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- readonly struct ScopedTemporaryBuffer : IDisposable
- {
- private readonly BufferManager _bufferManager;
- private readonly bool _isReserved;
-
- public readonly BufferRange Range;
- public readonly BufferHolder Holder;
-
- public BufferHandle Handle => Range.Handle;
- public int Offset => Range.Offset;
-
- public ScopedTemporaryBuffer(BufferManager bufferManager, BufferHolder holder, BufferHandle handle, int offset, int size, bool isReserved)
- {
- _bufferManager = bufferManager;
-
- Range = new BufferRange(handle, offset, size);
- Holder = holder;
-
- _isReserved = isReserved;
- }
-
- public void Dispose()
- {
- if (!_isReserved)
- {
- _bufferManager.Delete(Range.Handle);
- }
- }
- }
-
- [SupportedOSPlatform("macos")]
- class BufferManager : IDisposable
- {
- private readonly IdList _buffers;
-
- private readonly MTLDevice _device;
- private readonly MetalRenderer _renderer;
- private readonly Pipeline _pipeline;
-
- public int BufferCount { get; private set; }
-
- public StagingBuffer StagingBuffer { get; }
-
- public BufferManager(MTLDevice device, MetalRenderer renderer, Pipeline pipeline)
- {
- _device = device;
- _renderer = renderer;
- _pipeline = pipeline;
- _buffers = new IdList();
-
- StagingBuffer = new StagingBuffer(_renderer, this);
- }
-
- public BufferHandle Create(nint pointer, int size)
- {
- // TODO: This is the wrong Metal method, we need no-copy which SharpMetal isn't giving us.
- MTLBuffer buffer = _device.NewBuffer(pointer, (ulong)size, MTLResourceOptions.ResourceStorageModeShared);
-
- if (buffer == IntPtr.Zero)
- {
- Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create buffer with size 0x{size:X}, and pointer 0x{pointer:X}.");
-
- return BufferHandle.Null;
- }
-
- BufferHolder holder = new(_renderer, _pipeline, buffer, size);
-
- BufferCount++;
-
- ulong handle64 = (uint)_buffers.Add(holder);
-
- return Unsafe.As(ref handle64);
- }
-
- public BufferHandle CreateWithHandle(int size)
- {
- return CreateWithHandle(size, out _);
- }
-
- public BufferHandle CreateWithHandle(int size, out BufferHolder holder)
- {
- holder = Create(size);
-
- if (holder == null)
- {
- return BufferHandle.Null;
- }
-
- BufferCount++;
-
- ulong handle64 = (uint)_buffers.Add(holder);
-
- return Unsafe.As(ref handle64);
- }
-
- public ScopedTemporaryBuffer ReserveOrCreate(CommandBufferScoped cbs, int size)
- {
- StagingBufferReserved? result = StagingBuffer.TryReserveData(cbs, size);
-
- if (result.HasValue)
- {
- return new ScopedTemporaryBuffer(this, result.Value.Buffer, StagingBuffer.Handle, result.Value.Offset, result.Value.Size, true);
- }
- else
- {
- // Create a temporary buffer.
- BufferHandle handle = CreateWithHandle(size, out BufferHolder holder);
-
- return new ScopedTemporaryBuffer(this, holder, handle, 0, size, false);
- }
- }
-
- public BufferHolder Create(int size)
- {
- MTLBuffer buffer = _device.NewBuffer((ulong)size, MTLResourceOptions.ResourceStorageModeShared);
-
- if (buffer != IntPtr.Zero)
- {
- return new BufferHolder(_renderer, _pipeline, buffer, size);
- }
-
- Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create buffer with size 0x{size:X}.");
-
- return null;
- }
-
- public Auto GetBuffer(BufferHandle handle, bool isWrite, out int size)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- size = holder.Size;
- return holder.GetBuffer(isWrite);
- }
-
- size = 0;
- return null;
- }
-
- public Auto GetBuffer(BufferHandle handle, int offset, int size, bool isWrite)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- return holder.GetBuffer(offset, size, isWrite);
- }
-
- return null;
- }
-
- public Auto GetBuffer(BufferHandle handle, bool isWrite)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- return holder.GetBuffer(isWrite);
- }
-
- return null;
- }
-
- public Auto GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- return holder.GetBufferI8ToI16(cbs, offset, size);
- }
-
- return null;
- }
-
- public Auto GetBufferTopologyConversion(CommandBufferScoped cbs, BufferHandle handle, int offset, int size, IndexBufferPattern pattern, int indexSize)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- return holder.GetBufferTopologyConversion(cbs, offset, size, pattern, indexSize);
- }
-
- return null;
- }
-
- public PinnedSpan GetData(BufferHandle handle, int offset, int size)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- return holder.GetData(offset, size);
- }
-
- return new PinnedSpan();
- }
-
- public void SetData(BufferHandle handle, int offset, ReadOnlySpan data) where T : unmanaged
- {
- SetData(handle, offset, MemoryMarshal.Cast(data), null);
- }
-
- public void SetData(BufferHandle handle, int offset, ReadOnlySpan data, CommandBufferScoped? cbs)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- holder.SetData(offset, data, cbs);
- }
- }
-
- public void Delete(BufferHandle handle)
- {
- if (TryGetBuffer(handle, out BufferHolder holder))
- {
- holder.Dispose();
- _buffers.Remove((int)Unsafe.As(ref handle));
- }
- }
-
- private bool TryGetBuffer(BufferHandle handle, out BufferHolder holder)
- {
- return _buffers.TryGetValue((int)Unsafe.As(ref handle), out holder);
- }
-
- public void Dispose()
- {
- StagingBuffer.Dispose();
-
- foreach (BufferHolder buffer in _buffers)
- {
- buffer.Dispose();
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/BufferUsageBitmap.cs b/src/Ryujinx.Graphics.Metal/BufferUsageBitmap.cs
deleted file mode 100644
index 379e27407..000000000
--- a/src/Ryujinx.Graphics.Metal/BufferUsageBitmap.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- internal class BufferUsageBitmap
- {
- private readonly BitMap _bitmap;
- private readonly int _size;
- private readonly int _granularity;
- private readonly int _bits;
- private readonly int _writeBitOffset;
-
- private readonly int _intsPerCb;
- private readonly int _bitsPerCb;
-
- public BufferUsageBitmap(int size, int granularity)
- {
- _size = size;
- _granularity = granularity;
-
- // There are two sets of bits - one for read tracking, and the other for write.
- int bits = (size + (granularity - 1)) / granularity;
- _writeBitOffset = bits;
- _bits = bits << 1;
-
- _intsPerCb = (_bits + (BitMap.IntSize - 1)) / BitMap.IntSize;
- _bitsPerCb = _intsPerCb * BitMap.IntSize;
-
- _bitmap = new BitMap(_bitsPerCb * CommandBufferPool.MaxCommandBuffers);
- }
-
- public void Add(int cbIndex, int offset, int size, bool write)
- {
- if (size == 0)
- {
- return;
- }
-
- // Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
- if (offset + size > _size)
- {
- size = _size - offset;
- }
-
- int cbBase = cbIndex * _bitsPerCb + (write ? _writeBitOffset : 0);
- int start = cbBase + offset / _granularity;
- int end = cbBase + (offset + size - 1) / _granularity;
-
- _bitmap.SetRange(start, end);
- }
-
- public bool OverlapsWith(int cbIndex, int offset, int size, bool write = false)
- {
- if (size == 0)
- {
- return false;
- }
-
- int cbBase = cbIndex * _bitsPerCb + (write ? _writeBitOffset : 0);
- int start = cbBase + offset / _granularity;
- int end = cbBase + (offset + size - 1) / _granularity;
-
- return _bitmap.IsSet(start, end);
- }
-
- public bool OverlapsWith(int offset, int size, bool write)
- {
- for (int i = 0; i < CommandBufferPool.MaxCommandBuffers; i++)
- {
- if (OverlapsWith(i, offset, size, write))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public void Clear(int cbIndex)
- {
- _bitmap.ClearInt(cbIndex * _intsPerCb, (cbIndex + 1) * _intsPerCb - 1);
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/CacheByRange.cs b/src/Ryujinx.Graphics.Metal/CacheByRange.cs
deleted file mode 100644
index 2002eeba4..000000000
--- a/src/Ryujinx.Graphics.Metal/CacheByRange.cs
+++ /dev/null
@@ -1,294 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- interface ICacheKey : IDisposable
- {
- bool KeyEqual(ICacheKey other);
- }
-
- [SupportedOSPlatform("macos")]
- struct I8ToI16CacheKey : ICacheKey
- {
- // Used to notify the pipeline that bindings have invalidated on dispose.
- // private readonly MetalRenderer _renderer;
- // private Auto _buffer;
-
- public I8ToI16CacheKey(MetalRenderer renderer)
- {
- // _renderer = renderer;
- // _buffer = null;
- }
-
- public readonly bool KeyEqual(ICacheKey other)
- {
- return other is I8ToI16CacheKey;
- }
-
- public readonly void SetBuffer(Auto buffer)
- {
- // _buffer = buffer;
- }
-
- public readonly void Dispose()
- {
- // TODO: Tell pipeline buffer is dirty!
- // _renderer.PipelineInternal.DirtyIndexBuffer(_buffer);
- }
- }
-
- [SupportedOSPlatform("macos")]
- readonly struct TopologyConversionCacheKey : ICacheKey
- {
- private readonly IndexBufferPattern _pattern;
- private readonly int _indexSize;
-
- // Used to notify the pipeline that bindings have invalidated on dispose.
- // private readonly MetalRenderer _renderer;
- // private Auto _buffer;
-
- public TopologyConversionCacheKey(MetalRenderer renderer, IndexBufferPattern pattern, int indexSize)
- {
- // _renderer = renderer;
- // _buffer = null;
- _pattern = pattern;
- _indexSize = indexSize;
- }
-
- public readonly bool KeyEqual(ICacheKey other)
- {
- return other is TopologyConversionCacheKey entry &&
- entry._pattern == _pattern &&
- entry._indexSize == _indexSize;
- }
-
- public void SetBuffer(Auto buffer)
- {
- // _buffer = buffer;
- }
-
- public readonly void Dispose()
- {
- // TODO: Tell pipeline buffer is dirty!
- // _renderer.PipelineInternal.DirtyVertexBuffer(_buffer);
- }
- }
-
- [SupportedOSPlatform("macos")]
- readonly struct Dependency
- {
- private readonly BufferHolder _buffer;
- private readonly int _offset;
- private readonly int _size;
- private readonly ICacheKey _key;
-
- public Dependency(BufferHolder buffer, int offset, int size, ICacheKey key)
- {
- _buffer = buffer;
- _offset = offset;
- _size = size;
- _key = key;
- }
-
- public void RemoveFromOwner()
- {
- _buffer.RemoveCachedConvertedBuffer(_offset, _size, _key);
- }
- }
-
- [SupportedOSPlatform("macos")]
- struct CacheByRange where T : IDisposable
- {
- private struct Entry
- {
- public readonly ICacheKey Key;
- public readonly T Value;
- public List DependencyList;
-
- public Entry(ICacheKey key, T value)
- {
- Key = key;
- Value = value;
- DependencyList = null;
- }
-
- public readonly void InvalidateDependencies()
- {
- if (DependencyList != null)
- {
- foreach (Dependency dependency in DependencyList)
- {
- dependency.RemoveFromOwner();
- }
-
- DependencyList.Clear();
- }
- }
- }
-
- private Dictionary> _ranges;
-
- public void Add(int offset, int size, ICacheKey key, T value)
- {
- List entries = GetEntries(offset, size);
-
- entries.Add(new Entry(key, value));
- }
-
- public void AddDependency(int offset, int size, ICacheKey key, Dependency dependency)
- {
- List entries = GetEntries(offset, size);
-
- for (int i = 0; i < entries.Count; i++)
- {
- Entry entry = entries[i];
-
- if (entry.Key.KeyEqual(key))
- {
- if (entry.DependencyList == null)
- {
- entry.DependencyList = [];
- entries[i] = entry;
- }
-
- entry.DependencyList.Add(dependency);
-
- break;
- }
- }
- }
-
- public void Remove(int offset, int size, ICacheKey key)
- {
- List entries = GetEntries(offset, size);
-
- for (int i = 0; i < entries.Count; i++)
- {
- Entry entry = entries[i];
-
- if (entry.Key.KeyEqual(key))
- {
- entries.RemoveAt(i--);
-
- DestroyEntry(entry);
- }
- }
-
- if (entries.Count == 0)
- {
- _ranges.Remove(PackRange(offset, size));
- }
- }
-
- public bool TryGetValue(int offset, int size, ICacheKey key, out T value)
- {
- List entries = GetEntries(offset, size);
-
- foreach (Entry entry in entries)
- {
- if (entry.Key.KeyEqual(key))
- {
- value = entry.Value;
-
- return true;
- }
- }
-
- value = default;
- return false;
- }
-
- public void Clear()
- {
- if (_ranges != null)
- {
- foreach (List entries in _ranges.Values)
- {
- foreach (Entry entry in entries)
- {
- DestroyEntry(entry);
- }
- }
-
- _ranges.Clear();
- _ranges = null;
- }
- }
-
- public readonly void ClearRange(int offset, int size)
- {
- if (_ranges != null && _ranges.Count > 0)
- {
- int end = offset + size;
-
- List toRemove = null;
-
- foreach (KeyValuePair> range in _ranges)
- {
- (int rOffset, int rSize) = UnpackRange(range.Key);
-
- int rEnd = rOffset + rSize;
-
- if (rEnd > offset && rOffset < end)
- {
- List entries = range.Value;
-
- foreach (Entry entry in entries)
- {
- DestroyEntry(entry);
- }
-
- (toRemove ??= []).Add(range.Key);
- }
- }
-
- if (toRemove != null)
- {
- foreach (ulong range in toRemove)
- {
- _ranges.Remove(range);
- }
- }
- }
- }
-
- private List GetEntries(int offset, int size)
- {
- _ranges ??= new Dictionary>();
-
- ulong key = PackRange(offset, size);
-
- if (!_ranges.TryGetValue(key, out List value))
- {
- value = [];
- _ranges.Add(key, value);
- }
-
- return value;
- }
-
- private static void DestroyEntry(Entry entry)
- {
- entry.Key.Dispose();
- entry.Value?.Dispose();
- entry.InvalidateDependencies();
- }
-
- private static ulong PackRange(int offset, int size)
- {
- return (uint)offset | ((ulong)size << 32);
- }
-
- private static (int offset, int size) UnpackRange(ulong range)
- {
- return ((int)range, (int)(range >> 32));
- }
-
- public void Dispose()
- {
- Clear();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/CommandBufferEncoder.cs b/src/Ryujinx.Graphics.Metal/CommandBufferEncoder.cs
deleted file mode 100644
index 3bc30e239..000000000
--- a/src/Ryujinx.Graphics.Metal/CommandBufferEncoder.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-using Ryujinx.Graphics.Metal;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.Versioning;
-
-interface IEncoderFactory
-{
- MTLRenderCommandEncoder CreateRenderCommandEncoder();
- MTLComputeCommandEncoder CreateComputeCommandEncoder();
-}
-
-///
-/// Tracks active encoder object for a command buffer.
-///
-[SupportedOSPlatform("macos")]
-class CommandBufferEncoder
-{
- public EncoderType CurrentEncoderType { get; private set; } = EncoderType.None;
-
- public MTLBlitCommandEncoder BlitEncoder => new(CurrentEncoder.Value);
-
- public MTLComputeCommandEncoder ComputeEncoder => new(CurrentEncoder.Value);
-
- public MTLRenderCommandEncoder RenderEncoder => new(CurrentEncoder.Value);
-
- internal MTLCommandEncoder? CurrentEncoder { get; private set; }
-
- private MTLCommandBuffer _commandBuffer;
- private IEncoderFactory _encoderFactory;
-
- public void Initialize(MTLCommandBuffer commandBuffer, IEncoderFactory encoderFactory)
- {
- _commandBuffer = commandBuffer;
- _encoderFactory = encoderFactory;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public MTLRenderCommandEncoder EnsureRenderEncoder()
- {
- if (CurrentEncoderType != EncoderType.Render)
- {
- return BeginRenderPass();
- }
-
- return RenderEncoder;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public MTLBlitCommandEncoder EnsureBlitEncoder()
- {
- if (CurrentEncoderType != EncoderType.Blit)
- {
- return BeginBlitPass();
- }
-
- return BlitEncoder;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public MTLComputeCommandEncoder EnsureComputeEncoder()
- {
- if (CurrentEncoderType != EncoderType.Compute)
- {
- return BeginComputePass();
- }
-
- return ComputeEncoder;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetRenderEncoder(out MTLRenderCommandEncoder encoder)
- {
- if (CurrentEncoderType != EncoderType.Render)
- {
- encoder = default;
- return false;
- }
-
- encoder = RenderEncoder;
- return true;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetBlitEncoder(out MTLBlitCommandEncoder encoder)
- {
- if (CurrentEncoderType != EncoderType.Blit)
- {
- encoder = default;
- return false;
- }
-
- encoder = BlitEncoder;
- return true;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetComputeEncoder(out MTLComputeCommandEncoder encoder)
- {
- if (CurrentEncoderType != EncoderType.Compute)
- {
- encoder = default;
- return false;
- }
-
- encoder = ComputeEncoder;
- return true;
- }
-
- public void EndCurrentPass()
- {
- if (CurrentEncoder != null)
- {
- switch (CurrentEncoderType)
- {
- case EncoderType.Blit:
- BlitEncoder.EndEncoding();
- CurrentEncoder = null;
- break;
- case EncoderType.Compute:
- ComputeEncoder.EndEncoding();
- CurrentEncoder = null;
- break;
- case EncoderType.Render:
- RenderEncoder.EndEncoding();
- CurrentEncoder = null;
- break;
- default:
- throw new InvalidOperationException();
- }
-
- CurrentEncoderType = EncoderType.None;
- }
- }
-
- private MTLRenderCommandEncoder BeginRenderPass()
- {
- EndCurrentPass();
-
- MTLRenderCommandEncoder renderCommandEncoder = _encoderFactory.CreateRenderCommandEncoder();
-
- CurrentEncoder = renderCommandEncoder;
- CurrentEncoderType = EncoderType.Render;
-
- return renderCommandEncoder;
- }
-
- private MTLBlitCommandEncoder BeginBlitPass()
- {
- EndCurrentPass();
-
- using MTLBlitPassDescriptor descriptor = new();
- MTLBlitCommandEncoder blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
-
- CurrentEncoder = blitCommandEncoder;
- CurrentEncoderType = EncoderType.Blit;
- return blitCommandEncoder;
- }
-
- private MTLComputeCommandEncoder BeginComputePass()
- {
- EndCurrentPass();
-
- MTLComputeCommandEncoder computeCommandEncoder = _encoderFactory.CreateComputeCommandEncoder();
-
- CurrentEncoder = computeCommandEncoder;
- CurrentEncoderType = EncoderType.Compute;
- return computeCommandEncoder;
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/CommandBufferPool.cs b/src/Ryujinx.Graphics.Metal/CommandBufferPool.cs
deleted file mode 100644
index d8c35b757..000000000
--- a/src/Ryujinx.Graphics.Metal/CommandBufferPool.cs
+++ /dev/null
@@ -1,289 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.Versioning;
-using System.Threading;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class CommandBufferPool : IDisposable
- {
- public const int MaxCommandBuffers = 16;
-
- private readonly int _totalCommandBuffers;
- private readonly int _totalCommandBuffersMask;
- private readonly MTLCommandQueue _queue;
- private readonly Thread _owner;
- private IEncoderFactory _defaultEncoderFactory;
-
- public bool OwnedByCurrentThread => _owner == Thread.CurrentThread;
-
- [SupportedOSPlatform("macos")]
- private struct ReservedCommandBuffer
- {
- public bool InUse;
- public bool InConsumption;
- public int SubmissionCount;
- public MTLCommandBuffer CommandBuffer;
- public CommandBufferEncoder Encoders;
- public FenceHolder Fence;
-
- public List Dependants;
- public List Waitables;
-
- public void Use(MTLCommandQueue queue, IEncoderFactory stateManager)
- {
- MTLCommandBufferDescriptor descriptor = new();
-#if DEBUG
- descriptor.ErrorOptions = MTLCommandBufferErrorOption.EncoderExecutionStatus;
-#endif
-
- CommandBuffer = queue.CommandBuffer(descriptor);
- Fence = new FenceHolder(CommandBuffer);
-
- Encoders.Initialize(CommandBuffer, stateManager);
-
- InUse = true;
- }
-
- public void Initialize()
- {
- Dependants = [];
- Waitables = [];
- Encoders = new CommandBufferEncoder();
- }
- }
-
- private readonly ReservedCommandBuffer[] _commandBuffers;
-
- private readonly int[] _queuedIndexes;
- private int _queuedIndexesPtr;
- private int _queuedCount;
- private int _inUseCount;
-
- public CommandBufferPool(MTLCommandQueue queue, bool isLight = false)
- {
- _queue = queue;
- _owner = Thread.CurrentThread;
-
- _totalCommandBuffers = isLight ? 2 : MaxCommandBuffers;
- _totalCommandBuffersMask = _totalCommandBuffers - 1;
-
- _commandBuffers = new ReservedCommandBuffer[_totalCommandBuffers];
-
- _queuedIndexes = new int[_totalCommandBuffers];
- _queuedIndexesPtr = 0;
- _queuedCount = 0;
- }
-
- public void Initialize(IEncoderFactory encoderFactory)
- {
- _defaultEncoderFactory = encoderFactory;
-
- for (int i = 0; i < _totalCommandBuffers; i++)
- {
- _commandBuffers[i].Initialize();
- WaitAndDecrementRef(i);
- }
- }
-
- public void AddDependant(int cbIndex, IAuto dependant)
- {
- dependant.IncrementReferenceCount();
- _commandBuffers[cbIndex].Dependants.Add(dependant);
- }
-
- public void AddWaitable(MultiFenceHolder waitable)
- {
- lock (_commandBuffers)
- {
- for (int i = 0; i < _totalCommandBuffers; i++)
- {
- ref ReservedCommandBuffer entry = ref _commandBuffers[i];
-
- if (entry.InConsumption)
- {
- AddWaitable(i, waitable);
- }
- }
- }
- }
-
- public void AddInUseWaitable(MultiFenceHolder waitable)
- {
- lock (_commandBuffers)
- {
- for (int i = 0; i < _totalCommandBuffers; i++)
- {
- ref ReservedCommandBuffer entry = ref _commandBuffers[i];
-
- if (entry.InUse)
- {
- AddWaitable(i, waitable);
- }
- }
- }
- }
-
- public void AddWaitable(int cbIndex, MultiFenceHolder waitable)
- {
- ref ReservedCommandBuffer entry = ref _commandBuffers[cbIndex];
- if (waitable.AddFence(cbIndex, entry.Fence))
- {
- entry.Waitables.Add(waitable);
- }
- }
-
- public bool IsFenceOnRentedCommandBuffer(FenceHolder fence)
- {
- lock (_commandBuffers)
- {
- for (int i = 0; i < _totalCommandBuffers; i++)
- {
- ref ReservedCommandBuffer entry = ref _commandBuffers[i];
-
- if (entry.InUse && entry.Fence == fence)
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- public FenceHolder GetFence(int cbIndex)
- {
- return _commandBuffers[cbIndex].Fence;
- }
-
- public int GetSubmissionCount(int cbIndex)
- {
- return _commandBuffers[cbIndex].SubmissionCount;
- }
-
- private int FreeConsumed(bool wait)
- {
- int freeEntry = 0;
-
- while (_queuedCount > 0)
- {
- int index = _queuedIndexes[_queuedIndexesPtr];
-
- ref ReservedCommandBuffer entry = ref _commandBuffers[index];
-
- if (wait || !entry.InConsumption || entry.Fence.IsSignaled())
- {
- WaitAndDecrementRef(index);
-
- wait = false;
- freeEntry = index;
-
- _queuedCount--;
- _queuedIndexesPtr = (_queuedIndexesPtr + 1) % _totalCommandBuffers;
- }
- else
- {
- break;
- }
- }
-
- return freeEntry;
- }
-
- public CommandBufferScoped ReturnAndRent(CommandBufferScoped cbs)
- {
- Return(cbs);
- return Rent();
- }
-
- public CommandBufferScoped Rent()
- {
- lock (_commandBuffers)
- {
- int cursor = FreeConsumed(_inUseCount + _queuedCount == _totalCommandBuffers);
-
- for (int i = 0; i < _totalCommandBuffers; i++)
- {
- ref ReservedCommandBuffer entry = ref _commandBuffers[cursor];
-
- if (!entry.InUse && !entry.InConsumption)
- {
- entry.Use(_queue, _defaultEncoderFactory);
-
- _inUseCount++;
-
- return new CommandBufferScoped(this, entry.CommandBuffer, entry.Encoders, cursor);
- }
-
- cursor = (cursor + 1) & _totalCommandBuffersMask;
- }
- }
-
- throw new InvalidOperationException($"Out of command buffers (In use: {_inUseCount}, queued: {_queuedCount}, total: {_totalCommandBuffers})");
- }
-
- public void Return(CommandBufferScoped cbs)
- {
- // Ensure the encoder is committed.
- cbs.Encoders.EndCurrentPass();
-
- lock (_commandBuffers)
- {
- int cbIndex = cbs.CommandBufferIndex;
-
- ref ReservedCommandBuffer entry = ref _commandBuffers[cbIndex];
-
- Debug.Assert(entry.InUse);
- Debug.Assert(entry.CommandBuffer.NativePtr == cbs.CommandBuffer.NativePtr);
- entry.InUse = false;
- entry.InConsumption = true;
- entry.SubmissionCount++;
- _inUseCount--;
-
- MTLCommandBuffer commandBuffer = entry.CommandBuffer;
- commandBuffer.Commit();
-
- int ptr = (_queuedIndexesPtr + _queuedCount) % _totalCommandBuffers;
- _queuedIndexes[ptr] = cbIndex;
- _queuedCount++;
- }
- }
-
- private void WaitAndDecrementRef(int cbIndex)
- {
- ref ReservedCommandBuffer entry = ref _commandBuffers[cbIndex];
-
- if (entry.InConsumption)
- {
- entry.Fence.Wait();
- entry.InConsumption = false;
- }
-
- foreach (IAuto dependant in entry.Dependants)
- {
- dependant.DecrementReferenceCount(cbIndex);
- }
-
- foreach (MultiFenceHolder waitable in entry.Waitables)
- {
- waitable.RemoveFence(cbIndex);
- waitable.RemoveBufferUses(cbIndex);
- }
-
- entry.Dependants.Clear();
- entry.Waitables.Clear();
- entry.Fence?.Dispose();
- }
-
- public void Dispose()
- {
- for (int i = 0; i < _totalCommandBuffers; i++)
- {
- WaitAndDecrementRef(i);
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/CommandBufferScoped.cs b/src/Ryujinx.Graphics.Metal/CommandBufferScoped.cs
deleted file mode 100644
index 822f69b46..000000000
--- a/src/Ryujinx.Graphics.Metal/CommandBufferScoped.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- readonly struct CommandBufferScoped : IDisposable
- {
- private readonly CommandBufferPool _pool;
- public MTLCommandBuffer CommandBuffer { get; }
- public CommandBufferEncoder Encoders { get; }
- public int CommandBufferIndex { get; }
-
- public CommandBufferScoped(CommandBufferPool pool, MTLCommandBuffer commandBuffer, CommandBufferEncoder encoders, int commandBufferIndex)
- {
- _pool = pool;
- CommandBuffer = commandBuffer;
- Encoders = encoders;
- CommandBufferIndex = commandBufferIndex;
- }
-
- public void AddDependant(IAuto dependant)
- {
- _pool.AddDependant(CommandBufferIndex, dependant);
- }
-
- public void AddWaitable(MultiFenceHolder waitable)
- {
- _pool.AddWaitable(CommandBufferIndex, waitable);
- }
-
- public FenceHolder GetFence()
- {
- return _pool.GetFence(CommandBufferIndex);
- }
-
- public void Dispose()
- {
- _pool?.Return(this);
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Constants.cs b/src/Ryujinx.Graphics.Metal/Constants.cs
deleted file mode 100644
index 43baf722a..000000000
--- a/src/Ryujinx.Graphics.Metal/Constants.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-namespace Ryujinx.Graphics.Metal
-{
- static class Constants
- {
- public const int MaxShaderStages = 5;
- public const int MaxVertexBuffers = 16;
- public const int MaxUniformBuffersPerStage = 18;
- public const int MaxStorageBuffersPerStage = 16;
- public const int MaxTexturesPerStage = 64;
- public const int MaxImagesPerStage = 16;
-
- public const int MaxUniformBufferBindings = MaxUniformBuffersPerStage * MaxShaderStages;
- public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages;
- public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages;
- public const int MaxImageBindings = MaxImagesPerStage * MaxShaderStages;
- public const int MaxColorAttachments = 8;
- public const int MaxViewports = 16;
- // TODO: Check this value
- public const int MaxVertexAttributes = 31;
-
- public const int MinResourceAlignment = 16;
-
- // Must match constants set in shader generation
- public const uint ZeroBufferIndex = MaxVertexBuffers;
- public const uint BaseSetIndex = MaxVertexBuffers + 1;
-
- public const uint ConstantBuffersIndex = BaseSetIndex;
- public const uint StorageBuffersIndex = BaseSetIndex + 1;
- public const uint TexturesIndex = BaseSetIndex + 2;
- public const uint ImagesIndex = BaseSetIndex + 3;
-
- public const uint ConstantBuffersSetIndex = 0;
- public const uint StorageBuffersSetIndex = 1;
- public const uint TexturesSetIndex = 2;
- public const uint ImagesSetIndex = 3;
-
- public const uint MaximumBufferArgumentTableEntries = 31;
-
- public const uint MaximumExtraSets = MaximumBufferArgumentTableEntries - ImagesIndex;
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/CounterEvent.cs b/src/Ryujinx.Graphics.Metal/CounterEvent.cs
deleted file mode 100644
index 46b04997e..000000000
--- a/src/Ryujinx.Graphics.Metal/CounterEvent.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Metal
-{
- class CounterEvent : ICounterEvent
- {
- public CounterEvent()
- {
- Invalid = false;
- }
-
- public bool Invalid { get; set; }
- public bool ReserveForHostAccess()
- {
- return true;
- }
-
- public void Flush() { }
-
- public void Dispose() { }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/DepthStencilCache.cs b/src/Ryujinx.Graphics.Metal/DepthStencilCache.cs
deleted file mode 100644
index 47d996010..000000000
--- a/src/Ryujinx.Graphics.Metal/DepthStencilCache.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using Ryujinx.Graphics.Metal.State;
-using SharpMetal.Metal;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class DepthStencilCache : StateCache
- {
- private readonly MTLDevice _device;
-
- public DepthStencilCache(MTLDevice device)
- {
- _device = device;
- }
-
- protected override DepthStencilUid GetHash(DepthStencilUid descriptor)
- {
- return descriptor;
- }
-
- protected override MTLDepthStencilState CreateValue(DepthStencilUid descriptor)
- {
- // Create descriptors
-
- ref StencilUid frontUid = ref descriptor.FrontFace;
-
- using MTLStencilDescriptor frontFaceStencil = new()
- {
- StencilFailureOperation = frontUid.StencilFailureOperation,
- DepthFailureOperation = frontUid.DepthFailureOperation,
- DepthStencilPassOperation = frontUid.DepthStencilPassOperation,
- StencilCompareFunction = frontUid.StencilCompareFunction,
- ReadMask = frontUid.ReadMask,
- WriteMask = frontUid.WriteMask
- };
-
- ref StencilUid backUid = ref descriptor.BackFace;
-
- using MTLStencilDescriptor backFaceStencil = new()
- {
- StencilFailureOperation = backUid.StencilFailureOperation,
- DepthFailureOperation = backUid.DepthFailureOperation,
- DepthStencilPassOperation = backUid.DepthStencilPassOperation,
- StencilCompareFunction = backUid.StencilCompareFunction,
- ReadMask = backUid.ReadMask,
- WriteMask = backUid.WriteMask
- };
-
- MTLDepthStencilDescriptor mtlDescriptor = new()
- {
- DepthCompareFunction = descriptor.DepthCompareFunction,
- DepthWriteEnabled = descriptor.DepthWriteEnabled
- };
-
- if (descriptor.StencilTestEnabled)
- {
- mtlDescriptor.BackFaceStencil = backFaceStencil;
- mtlDescriptor.FrontFaceStencil = frontFaceStencil;
- }
-
- using (mtlDescriptor)
- {
- return _device.NewDepthStencilState(mtlDescriptor);
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/DisposableBuffer.cs b/src/Ryujinx.Graphics.Metal/DisposableBuffer.cs
deleted file mode 100644
index a2d2247c4..000000000
--- a/src/Ryujinx.Graphics.Metal/DisposableBuffer.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- readonly struct DisposableBuffer : IDisposable
- {
- public MTLBuffer Value { get; }
-
- public DisposableBuffer(MTLBuffer buffer)
- {
- Value = buffer;
- }
-
- public void Dispose()
- {
- if (Value != IntPtr.Zero)
- {
- Value.SetPurgeableState(MTLPurgeableState.Empty);
- Value.Dispose();
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/DisposableSampler.cs b/src/Ryujinx.Graphics.Metal/DisposableSampler.cs
deleted file mode 100644
index ba041be89..000000000
--- a/src/Ryujinx.Graphics.Metal/DisposableSampler.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- readonly struct DisposableSampler : IDisposable
- {
- public MTLSamplerState Value { get; }
-
- public DisposableSampler(MTLSamplerState sampler)
- {
- Value = sampler;
- }
-
- public void Dispose()
- {
- Value.Dispose();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Effects/IPostProcessingEffect.cs b/src/Ryujinx.Graphics.Metal/Effects/IPostProcessingEffect.cs
deleted file mode 100644
index d575d521f..000000000
--- a/src/Ryujinx.Graphics.Metal/Effects/IPostProcessingEffect.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Metal.Effects
-{
- internal interface IPostProcessingEffect : IDisposable
- {
- const int LocalGroupSize = 64;
- Texture Run(Texture view, int width, int height);
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Effects/IScalingFilter.cs b/src/Ryujinx.Graphics.Metal/Effects/IScalingFilter.cs
deleted file mode 100644
index 19f1a3c3d..000000000
--- a/src/Ryujinx.Graphics.Metal/Effects/IScalingFilter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using System;
-
-namespace Ryujinx.Graphics.Metal.Effects
-{
- internal interface IScalingFilter : IDisposable
- {
- float Level { get; set; }
- void Run(
- Texture view,
- Texture destinationTexture,
- Format format,
- int width,
- int height,
- Extents2D source,
- Extents2D destination);
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/EncoderResources.cs b/src/Ryujinx.Graphics.Metal/EncoderResources.cs
deleted file mode 100644
index 8b856c1ce..000000000
--- a/src/Ryujinx.Graphics.Metal/EncoderResources.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using SharpMetal.Metal;
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Metal
-{
- public struct RenderEncoderBindings
- {
- public List Resources = [];
- public List VertexBuffers = [];
- public List FragmentBuffers = [];
-
- public RenderEncoderBindings() { }
-
- public readonly void Clear()
- {
- Resources.Clear();
- VertexBuffers.Clear();
- FragmentBuffers.Clear();
- }
- }
-
- public struct ComputeEncoderBindings
- {
- public List Resources = [];
- public List Buffers = [];
-
- public ComputeEncoderBindings() { }
-
- public readonly void Clear()
- {
- Resources.Clear();
- Buffers.Clear();
- }
- }
-
- public struct BufferResource
- {
- public MTLBuffer Buffer;
- public ulong Offset;
- public ulong Binding;
-
- public BufferResource(MTLBuffer buffer, ulong offset, ulong binding)
- {
- Buffer = buffer;
- Offset = offset;
- Binding = binding;
- }
- }
-
- public struct Resource
- {
- public MTLResource MtlResource;
- public MTLResourceUsage ResourceUsage;
- public MTLRenderStages Stages;
-
- public Resource(MTLResource resource, MTLResourceUsage resourceUsage, MTLRenderStages stages)
- {
- MtlResource = resource;
- ResourceUsage = resourceUsage;
- Stages = stages;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/EncoderState.cs b/src/Ryujinx.Graphics.Metal/EncoderState.cs
deleted file mode 100644
index 64c50d71b..000000000
--- a/src/Ryujinx.Graphics.Metal/EncoderState.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-using Ryujinx.Common.Memory;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Metal.State;
-using Ryujinx.Graphics.Shader;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [Flags]
- enum DirtyFlags
- {
- None = 0,
- RenderPipeline = 1 << 0,
- ComputePipeline = 1 << 1,
- DepthStencil = 1 << 2,
- DepthClamp = 1 << 3,
- DepthBias = 1 << 4,
- CullMode = 1 << 5,
- FrontFace = 1 << 6,
- StencilRef = 1 << 7,
- Viewports = 1 << 8,
- Scissors = 1 << 9,
- Uniforms = 1 << 10,
- Storages = 1 << 11,
- Textures = 1 << 12,
- Images = 1 << 13,
-
- ArgBuffers = Uniforms | Storages | Textures | Images,
-
- RenderAll = RenderPipeline | DepthStencil | DepthClamp | DepthBias | CullMode | FrontFace | StencilRef | Viewports | Scissors | ArgBuffers,
- ComputeAll = ComputePipeline | ArgBuffers,
- All = RenderAll | ComputeAll,
- }
-
- record struct BufferRef
- {
- public Auto Buffer;
- public BufferRange? Range;
-
- public BufferRef(Auto buffer)
- {
- Buffer = buffer;
- }
-
- public BufferRef(Auto buffer, ref BufferRange range)
- {
- Buffer = buffer;
- Range = range;
- }
- }
-
- record struct TextureRef
- {
- public ShaderStage Stage;
- public TextureBase Storage;
- public Auto Sampler;
- public Format ImageFormat;
-
- public TextureRef(ShaderStage stage, TextureBase storage, Auto sampler)
- {
- Stage = stage;
- Storage = storage;
- Sampler = sampler;
- }
- }
-
- record struct ImageRef
- {
- public ShaderStage Stage;
- public Texture Storage;
-
- public ImageRef(ShaderStage stage, Texture storage)
- {
- Stage = stage;
- Storage = storage;
- }
- }
-
- struct PredrawState
- {
- public MTLCullMode CullMode;
- public DepthStencilUid DepthStencilUid;
- public PrimitiveTopology Topology;
- public MTLViewport[] Viewports;
- }
-
- struct RenderTargetCopy
- {
- public MTLScissorRect[] Scissors;
- public Texture DepthStencil;
- public Texture[] RenderTargets;
- }
-
- [SupportedOSPlatform("macos")]
- class EncoderState
- {
- public Program RenderProgram = null;
- public Program ComputeProgram = null;
-
- public PipelineState Pipeline;
- public DepthStencilUid DepthStencilUid;
-
- public readonly record struct ArrayRef(ShaderStage Stage, T Array);
-
- public readonly BufferRef[] UniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings];
- public readonly BufferRef[] StorageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings];
- public readonly TextureRef[] TextureRefs = new TextureRef[Constants.MaxTextureBindings * 2];
- public readonly ImageRef[] ImageRefs = new ImageRef[Constants.MaxImageBindings * 2];
-
- public ArrayRef[] TextureArrayRefs = [];
- public ArrayRef[] ImageArrayRefs = [];
-
- public ArrayRef[] TextureArrayExtraRefs = [];
- public ArrayRef[] ImageArrayExtraRefs = [];
-
- public IndexBufferState IndexBuffer = default;
-
- public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip;
-
- public float DepthBias;
- public float SlopeScale;
- public float Clamp;
-
- public int BackRefValue = 0;
- public int FrontRefValue = 0;
-
- public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
- public MTLCullMode CullMode = MTLCullMode.None;
- public MTLWinding Winding = MTLWinding.CounterClockwise;
- public bool CullBoth = false;
-
- public MTLViewport[] Viewports = new MTLViewport[Constants.MaxViewports];
- public MTLScissorRect[] Scissors = new MTLScissorRect[Constants.MaxViewports];
-
- // Changes to attachments take recreation!
- public Texture DepthStencil;
- public Texture[] RenderTargets = new Texture[Constants.MaxColorAttachments];
- public ITexture PreMaskDepthStencil = default;
- public ITexture[] PreMaskRenderTargets;
- public bool FramebufferUsingColorWriteMask;
-
- public Array8 StoredBlend;
- public ColorF BlendColor = new();
-
- public readonly VertexBufferState[] VertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers];
- public readonly VertexAttribDescriptor[] VertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttributes];
- // Dirty flags
- public DirtyFlags Dirty = DirtyFlags.None;
-
- // Only to be used for present
- public bool ClearLoadAction = false;
-
- public RenderEncoderBindings RenderEncoderBindings = new();
- public ComputeEncoderBindings ComputeEncoderBindings = new();
-
- public EncoderState()
- {
- Pipeline.Initialize();
- DepthStencilUid.DepthCompareFunction = MTLCompareFunction.Always;
- }
-
- public RenderTargetCopy InheritForClear(EncoderState other, bool depth, int singleIndex = -1)
- {
- // Inherit render target related information without causing a render encoder split.
-
- RenderTargetCopy oldState = new()
- {
- Scissors = other.Scissors,
- RenderTargets = other.RenderTargets,
- DepthStencil = other.DepthStencil
- };
-
- Scissors = other.Scissors;
- RenderTargets = other.RenderTargets;
- DepthStencil = other.DepthStencil;
-
- Pipeline.ColorBlendAttachmentStateCount = other.Pipeline.ColorBlendAttachmentStateCount;
- Pipeline.Internal.ColorBlendState = other.Pipeline.Internal.ColorBlendState;
- Pipeline.DepthStencilFormat = other.Pipeline.DepthStencilFormat;
-
- ref Array8 blendStates = ref Pipeline.Internal.ColorBlendState;
-
- // Mask out irrelevant attachments.
- for (int i = 0; i < blendStates.Length; i++)
- {
- if (depth || (singleIndex != -1 && singleIndex != i))
- {
- blendStates[i].WriteMask = MTLColorWriteMask.None;
- }
- }
-
- return oldState;
- }
-
- public void Restore(RenderTargetCopy copy)
- {
- Scissors = copy.Scissors;
- RenderTargets = copy.RenderTargets;
- DepthStencil = copy.DepthStencil;
-
- Pipeline.Internal.ResetColorState();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
deleted file mode 100644
index 7901e5a52..000000000
--- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
+++ /dev/null
@@ -1,1790 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Common.Memory;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Metal.State;
-using Ryujinx.Graphics.Shader;
-using SharpMetal.Metal;
-using System;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-using BufferAssignment = Ryujinx.Graphics.GAL.BufferAssignment;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- struct EncoderStateManager : IDisposable
- {
- private const int ArrayGrowthSize = 16;
-
- private readonly MTLDevice _device;
- private readonly Pipeline _pipeline;
- private readonly BufferManager _bufferManager;
-
- private readonly DepthStencilCache _depthStencilCache;
- private readonly MTLDepthStencilState _defaultState;
-
- private readonly EncoderState _mainState = new();
- private EncoderState _currentState;
-
- public readonly IndexBufferState IndexBuffer => _currentState.IndexBuffer;
- public readonly PrimitiveTopology Topology => _currentState.Topology;
- public readonly Texture[] RenderTargets => _currentState.RenderTargets;
- public readonly Texture DepthStencil => _currentState.DepthStencil;
- public readonly ComputeSize ComputeLocalSize => _currentState.ComputeProgram.ComputeLocalSize;
-
- // RGBA32F is the biggest format
- private const int ZeroBufferSize = 4 * 4;
- private readonly BufferHandle _zeroBuffer;
-
- public unsafe EncoderStateManager(MTLDevice device, BufferManager bufferManager, Pipeline pipeline)
- {
- _device = device;
- _pipeline = pipeline;
- _bufferManager = bufferManager;
-
- _depthStencilCache = new(device);
- _currentState = _mainState;
-
- _defaultState = _depthStencilCache.GetOrCreate(_currentState.DepthStencilUid);
-
- // Zero buffer
- byte[] zeros = new byte[ZeroBufferSize];
- fixed (byte* ptr = zeros)
- {
- _zeroBuffer = _bufferManager.Create((IntPtr)ptr, ZeroBufferSize);
- }
- }
-
- public readonly void Dispose()
- {
- _depthStencilCache.Dispose();
- }
-
- private readonly void SignalDirty(DirtyFlags flags)
- {
- _currentState.Dirty |= flags;
- }
-
- public readonly void SignalRenderDirty()
- {
- SignalDirty(DirtyFlags.RenderAll);
- }
-
- public readonly void SignalComputeDirty()
- {
- SignalDirty(DirtyFlags.ComputeAll);
- }
-
- public EncoderState SwapState(EncoderState state, DirtyFlags flags = DirtyFlags.All)
- {
- _currentState = state ?? _mainState;
-
- SignalDirty(flags);
-
- return _mainState;
- }
-
- public PredrawState SavePredrawState()
- {
- return new PredrawState
- {
- CullMode = _currentState.CullMode,
- DepthStencilUid = _currentState.DepthStencilUid,
- Topology = _currentState.Topology,
- Viewports = _currentState.Viewports.ToArray(),
- };
- }
-
- public readonly void RestorePredrawState(PredrawState state)
- {
- _currentState.CullMode = state.CullMode;
- _currentState.DepthStencilUid = state.DepthStencilUid;
- _currentState.Topology = state.Topology;
- _currentState.Viewports = state.Viewports;
-
- SignalDirty(DirtyFlags.CullMode | DirtyFlags.DepthStencil | DirtyFlags.Viewports);
- }
-
- public readonly void SetClearLoadAction(bool clear)
- {
- _currentState.ClearLoadAction = clear;
- }
-
- public readonly void DirtyTextures()
- {
- SignalDirty(DirtyFlags.Textures);
- }
-
- public readonly void DirtyImages()
- {
- SignalDirty(DirtyFlags.Images);
- }
-
- public readonly MTLRenderCommandEncoder CreateRenderCommandEncoder()
- {
- // Initialise Pass & State
- using MTLRenderPassDescriptor renderPassDescriptor = new();
-
- for (int i = 0; i < Constants.MaxColorAttachments; i++)
- {
- if (_currentState.RenderTargets[i] is Texture tex)
- {
- MTLRenderPassColorAttachmentDescriptor passAttachment = renderPassDescriptor.ColorAttachments.Object((ulong)i);
- tex.PopulateRenderPassAttachment(passAttachment);
- passAttachment.LoadAction = _currentState.ClearLoadAction ? MTLLoadAction.Clear : MTLLoadAction.Load;
- passAttachment.StoreAction = MTLStoreAction.Store;
- }
- }
-
- MTLRenderPassDepthAttachmentDescriptor depthAttachment = renderPassDescriptor.DepthAttachment;
- MTLRenderPassStencilAttachmentDescriptor stencilAttachment = renderPassDescriptor.StencilAttachment;
-
- if (_currentState.DepthStencil != null)
- {
- switch (_currentState.DepthStencil.GetHandle().PixelFormat)
- {
- // Depth Only Attachment
- case MTLPixelFormat.Depth16Unorm:
- case MTLPixelFormat.Depth32Float:
- depthAttachment.Texture = _currentState.DepthStencil.GetHandle();
- depthAttachment.LoadAction = MTLLoadAction.Load;
- depthAttachment.StoreAction = MTLStoreAction.Store;
- break;
-
- // Stencil Only Attachment
- case MTLPixelFormat.Stencil8:
- stencilAttachment.Texture = _currentState.DepthStencil.GetHandle();
- stencilAttachment.LoadAction = MTLLoadAction.Load;
- stencilAttachment.StoreAction = MTLStoreAction.Store;
- break;
-
- // Combined Attachment
- case MTLPixelFormat.Depth24UnormStencil8:
- case MTLPixelFormat.Depth32FloatStencil8:
- depthAttachment.Texture = _currentState.DepthStencil.GetHandle();
- depthAttachment.LoadAction = MTLLoadAction.Load;
- depthAttachment.StoreAction = MTLStoreAction.Store;
-
- stencilAttachment.Texture = _currentState.DepthStencil.GetHandle();
- stencilAttachment.LoadAction = MTLLoadAction.Load;
- stencilAttachment.StoreAction = MTLStoreAction.Store;
- break;
- default:
- Logger.Error?.PrintMsg(LogClass.Gpu, $"Unsupported Depth/Stencil Format: {_currentState.DepthStencil.GetHandle().PixelFormat}!");
- break;
- }
- }
-
- // Initialise Encoder
- MTLRenderCommandEncoder renderCommandEncoder = _pipeline.CommandBuffer.RenderCommandEncoder(renderPassDescriptor);
-
- return renderCommandEncoder;
- }
-
- public readonly MTLComputeCommandEncoder CreateComputeCommandEncoder()
- {
- using MTLComputePassDescriptor descriptor = new();
- MTLComputeCommandEncoder computeCommandEncoder = _pipeline.CommandBuffer.ComputeCommandEncoder(descriptor);
-
- return computeCommandEncoder;
- }
-
- public readonly void RenderResourcesPrepass()
- {
- _currentState.RenderEncoderBindings.Clear();
-
- if ((_currentState.Dirty & DirtyFlags.RenderPipeline) != 0)
- {
- SetVertexBuffers(_currentState.VertexBuffers, ref _currentState.RenderEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Uniforms) != 0)
- {
- UpdateAndBind(_currentState.RenderProgram, Constants.ConstantBuffersSetIndex, ref _currentState.RenderEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Storages) != 0)
- {
- UpdateAndBind(_currentState.RenderProgram, Constants.StorageBuffersSetIndex, ref _currentState.RenderEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Textures) != 0)
- {
- UpdateAndBind(_currentState.RenderProgram, Constants.TexturesSetIndex, ref _currentState.RenderEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Images) != 0)
- {
- UpdateAndBind(_currentState.RenderProgram, Constants.ImagesSetIndex, ref _currentState.RenderEncoderBindings);
- }
- }
-
- public readonly void ComputeResourcesPrepass()
- {
- _currentState.ComputeEncoderBindings.Clear();
-
- if ((_currentState.Dirty & DirtyFlags.Uniforms) != 0)
- {
- UpdateAndBind(_currentState.ComputeProgram, Constants.ConstantBuffersSetIndex, ref _currentState.ComputeEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Storages) != 0)
- {
- UpdateAndBind(_currentState.ComputeProgram, Constants.StorageBuffersSetIndex, ref _currentState.ComputeEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Textures) != 0)
- {
- UpdateAndBind(_currentState.ComputeProgram, Constants.TexturesSetIndex, ref _currentState.ComputeEncoderBindings);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Images) != 0)
- {
- UpdateAndBind(_currentState.ComputeProgram, Constants.ImagesSetIndex, ref _currentState.ComputeEncoderBindings);
- }
- }
-
- public void RebindRenderState(MTLRenderCommandEncoder renderCommandEncoder)
- {
- if ((_currentState.Dirty & DirtyFlags.RenderPipeline) != 0)
- {
- SetRenderPipelineState(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.DepthStencil) != 0)
- {
- SetDepthStencilState(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.DepthClamp) != 0)
- {
- SetDepthClamp(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.DepthBias) != 0)
- {
- SetDepthBias(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.CullMode) != 0)
- {
- SetCullMode(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.FrontFace) != 0)
- {
- SetFrontFace(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.StencilRef) != 0)
- {
- SetStencilRefValue(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Viewports) != 0)
- {
- SetViewports(renderCommandEncoder);
- }
-
- if ((_currentState.Dirty & DirtyFlags.Scissors) != 0)
- {
- SetScissors(renderCommandEncoder);
- }
-
- foreach (Resource resource in _currentState.RenderEncoderBindings.Resources)
- {
- renderCommandEncoder.UseResource(resource.MtlResource, resource.ResourceUsage, resource.Stages);
- }
-
- foreach (BufferResource buffer in _currentState.RenderEncoderBindings.VertexBuffers)
- {
- renderCommandEncoder.SetVertexBuffer(buffer.Buffer, buffer.Offset, buffer.Binding);
- }
-
- foreach (BufferResource buffer in _currentState.RenderEncoderBindings.FragmentBuffers)
- {
- renderCommandEncoder.SetFragmentBuffer(buffer.Buffer, buffer.Offset, buffer.Binding);
- }
-
- _currentState.Dirty &= ~DirtyFlags.RenderAll;
- }
-
- public readonly void RebindComputeState(MTLComputeCommandEncoder computeCommandEncoder)
- {
- if ((_currentState.Dirty & DirtyFlags.ComputePipeline) != 0)
- {
- SetComputePipelineState(computeCommandEncoder);
- }
-
- foreach (Resource resource in _currentState.ComputeEncoderBindings.Resources)
- {
- computeCommandEncoder.UseResource(resource.MtlResource, resource.ResourceUsage);
- }
-
- foreach (BufferResource buffer in _currentState.ComputeEncoderBindings.Buffers)
- {
- computeCommandEncoder.SetBuffer(buffer.Buffer, buffer.Offset, buffer.Binding);
- }
-
- _currentState.Dirty &= ~DirtyFlags.ComputeAll;
- }
-
- private readonly void SetRenderPipelineState(MTLRenderCommandEncoder renderCommandEncoder)
- {
- MTLRenderPipelineState pipelineState = _currentState.Pipeline.CreateRenderPipeline(_device, _currentState.RenderProgram);
-
- renderCommandEncoder.SetRenderPipelineState(pipelineState);
-
- renderCommandEncoder.SetBlendColor(
- _currentState.BlendColor.Red,
- _currentState.BlendColor.Green,
- _currentState.BlendColor.Blue,
- _currentState.BlendColor.Alpha);
- }
-
- private readonly void SetComputePipelineState(MTLComputeCommandEncoder computeCommandEncoder)
- {
- if (_currentState.ComputeProgram == null)
- {
- return;
- }
-
- MTLComputePipelineState pipelineState = PipelineState.CreateComputePipeline(_device, _currentState.ComputeProgram);
-
- computeCommandEncoder.SetComputePipelineState(pipelineState);
- }
-
- public readonly void UpdateIndexBuffer(BufferRange buffer, IndexType type)
- {
- if (buffer.Handle != BufferHandle.Null)
- {
- _currentState.IndexBuffer = new IndexBufferState(buffer.Handle, buffer.Offset, buffer.Size, type);
- }
- else
- {
- _currentState.IndexBuffer = IndexBufferState.Null;
- }
- }
-
- public readonly void UpdatePrimitiveTopology(PrimitiveTopology topology)
- {
- _currentState.Topology = topology;
- }
-
- public readonly void UpdateProgram(IProgram program)
- {
- Program prg = (Program)program;
-
- if (prg.VertexFunction == IntPtr.Zero && prg.ComputeFunction == IntPtr.Zero)
- {
- if (prg.FragmentFunction == IntPtr.Zero)
- {
- Logger.Error?.PrintMsg(LogClass.Gpu, "No compute function");
- }
- else
- {
- Logger.Error?.PrintMsg(LogClass.Gpu, "No vertex function");
- }
- return;
- }
-
- if (prg.VertexFunction != IntPtr.Zero)
- {
- _currentState.RenderProgram = prg;
-
- SignalDirty(DirtyFlags.RenderPipeline | DirtyFlags.ArgBuffers);
- }
- else if (prg.ComputeFunction != IntPtr.Zero)
- {
- _currentState.ComputeProgram = prg;
-
- SignalDirty(DirtyFlags.ComputePipeline | DirtyFlags.ArgBuffers);
- }
- }
-
- public readonly void UpdateRasterizerDiscard(bool discard)
- {
- _currentState.Pipeline.RasterizerDiscardEnable = discard;
-
- SignalDirty(DirtyFlags.RenderPipeline);
- }
-
- public readonly void UpdateRenderTargets(ITexture[] colors, ITexture depthStencil)
- {
- _currentState.FramebufferUsingColorWriteMask = false;
- UpdateRenderTargetsInternal(colors, depthStencil);
- }
-
- public readonly void UpdateRenderTargetColorMasks(ReadOnlySpan componentMask)
- {
- ref Array8 blendState = ref _currentState.Pipeline.Internal.ColorBlendState;
-
- for (int i = 0; i < componentMask.Length; i++)
- {
- bool red = (componentMask[i] & (0x1 << 0)) != 0;
- bool green = (componentMask[i] & (0x1 << 1)) != 0;
- bool blue = (componentMask[i] & (0x1 << 2)) != 0;
- bool alpha = (componentMask[i] & (0x1 << 3)) != 0;
-
- MTLColorWriteMask mask = MTLColorWriteMask.None;
-
- mask |= red ? MTLColorWriteMask.Red : 0;
- mask |= green ? MTLColorWriteMask.Green : 0;
- mask |= blue ? MTLColorWriteMask.Blue : 0;
- mask |= alpha ? MTLColorWriteMask.Alpha : 0;
-
- ref ColorBlendStateUid mtlBlend = ref blendState[i];
-
- // When color write mask is 0, remove all blend state to help the pipeline cache.
- // Restore it when the mask becomes non-zero.
- if (mtlBlend.WriteMask != mask)
- {
- if (mask == 0)
- {
- _currentState.StoredBlend[i] = mtlBlend;
-
- mtlBlend.Swap(new ColorBlendStateUid());
- }
- else if (mtlBlend.WriteMask == 0)
- {
- mtlBlend.Swap(_currentState.StoredBlend[i]);
- }
- }
-
- blendState[i].WriteMask = mask;
- }
-
- if (_currentState.FramebufferUsingColorWriteMask)
- {
- UpdateRenderTargetsInternal(_currentState.PreMaskRenderTargets, _currentState.PreMaskDepthStencil);
- }
- else
- {
- // Requires recreating pipeline
- if (_pipeline.CurrentEncoderType == EncoderType.Render)
- {
- _pipeline.EndCurrentPass();
- }
- }
- }
-
- private readonly void UpdateRenderTargetsInternal(ITexture[] colors, ITexture depthStencil)
- {
- // TBDR GPUs don't work properly if the same attachment is bound to multiple targets,
- // due to each attachment being a copy of the real attachment, rather than a direct write.
- //
- // Just try to remove duplicate attachments.
- // Save a copy of the array to rebind when mask changes.
-
- // Look for textures that are masked out.
-
- ref PipelineState pipeline = ref _currentState.Pipeline;
- ref Array8 blendState = ref pipeline.Internal.ColorBlendState;
-
- pipeline.ColorBlendAttachmentStateCount = (uint)colors.Length;
-
- for (int i = 0; i < colors.Length; i++)
- {
- if (colors[i] == null)
- {
- continue;
- }
-
- MTLColorWriteMask mtlMask = blendState[i].WriteMask;
-
- for (int j = 0; j < i; j++)
- {
- // Check each binding for a duplicate binding before it.
-
- if (colors[i] == colors[j])
- {
- // Prefer the binding with no write mask.
-
- MTLColorWriteMask mtlMask2 = blendState[j].WriteMask;
-
- if (mtlMask == 0)
- {
- colors[i] = null;
- MaskOut(colors, depthStencil);
- }
- else if (mtlMask2 == 0)
- {
- colors[j] = null;
- MaskOut(colors, depthStencil);
- }
- }
- }
- }
-
- _currentState.RenderTargets = new Texture[Constants.MaxColorAttachments];
-
- for (int i = 0; i < colors.Length; i++)
- {
- if (colors[i] is not Texture tex)
- {
- blendState[i].PixelFormat = MTLPixelFormat.Invalid;
-
- continue;
- }
-
- blendState[i].PixelFormat = tex.GetHandle().PixelFormat; // TODO: cache this
- _currentState.RenderTargets[i] = tex;
- }
-
- if (depthStencil is Texture depthTexture)
- {
- pipeline.DepthStencilFormat = depthTexture.GetHandle().PixelFormat; // TODO: cache this
- _currentState.DepthStencil = depthTexture;
- }
- else if (depthStencil == null)
- {
- pipeline.DepthStencilFormat = MTLPixelFormat.Invalid;
- _currentState.DepthStencil = null;
- }
-
- // Requires recreating pipeline
- if (_pipeline.CurrentEncoderType == EncoderType.Render)
- {
- _pipeline.EndCurrentPass();
- }
- }
-
- private readonly void MaskOut(ITexture[] colors, ITexture depthStencil)
- {
- if (!_currentState.FramebufferUsingColorWriteMask)
- {
- _currentState.PreMaskRenderTargets = colors;
- _currentState.PreMaskDepthStencil = depthStencil;
- }
-
- // If true, then the framebuffer must be recreated when the mask changes.
- _currentState.FramebufferUsingColorWriteMask = true;
- }
-
- public readonly void UpdateVertexAttribs(ReadOnlySpan vertexAttribs)
- {
- vertexAttribs.CopyTo(_currentState.VertexAttribs);
-
- // Update the buffers on the pipeline
- UpdatePipelineVertexState(_currentState.VertexBuffers, _currentState.VertexAttribs);
-
- SignalDirty(DirtyFlags.RenderPipeline);
- }
-
- public readonly void UpdateBlendDescriptors(int index, BlendDescriptor blend)
- {
- ref ColorBlendStateUid blendState = ref _currentState.Pipeline.Internal.ColorBlendState[index];
-
- blendState.Enable = blend.Enable;
- blendState.AlphaBlendOperation = blend.AlphaOp.Convert();
- blendState.RgbBlendOperation = blend.ColorOp.Convert();
- blendState.SourceAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
- blendState.DestinationAlphaBlendFactor = blend.AlphaDstFactor.Convert();
- blendState.SourceRGBBlendFactor = blend.ColorSrcFactor.Convert();
- blendState.DestinationRGBBlendFactor = blend.ColorDstFactor.Convert();
-
- if (blendState.WriteMask == 0)
- {
- _currentState.StoredBlend[index] = blendState;
-
- blendState.Swap(new ColorBlendStateUid());
- }
-
- _currentState.BlendColor = blend.BlendConstant;
-
- SignalDirty(DirtyFlags.RenderPipeline);
- }
-
- public void UpdateStencilState(StencilTestDescriptor stencilTest)
- {
- ref DepthStencilUid uid = ref _currentState.DepthStencilUid;
-
- uid.FrontFace = new StencilUid
- {
- StencilFailureOperation = stencilTest.FrontSFail.Convert(),
- DepthFailureOperation = stencilTest.FrontDpFail.Convert(),
- DepthStencilPassOperation = stencilTest.FrontDpPass.Convert(),
- StencilCompareFunction = stencilTest.FrontFunc.Convert(),
- ReadMask = (uint)stencilTest.FrontFuncMask,
- WriteMask = (uint)stencilTest.FrontMask
- };
-
- uid.BackFace = new StencilUid
- {
- StencilFailureOperation = stencilTest.BackSFail.Convert(),
- DepthFailureOperation = stencilTest.BackDpFail.Convert(),
- DepthStencilPassOperation = stencilTest.BackDpPass.Convert(),
- StencilCompareFunction = stencilTest.BackFunc.Convert(),
- ReadMask = (uint)stencilTest.BackFuncMask,
- WriteMask = (uint)stencilTest.BackMask
- };
-
- uid.StencilTestEnabled = stencilTest.TestEnable;
-
- UpdateStencilRefValue(stencilTest.FrontFuncRef, stencilTest.BackFuncRef);
-
- SignalDirty(DirtyFlags.DepthStencil);
- }
-
- public readonly void UpdateDepthState(DepthTestDescriptor depthTest)
- {
- ref DepthStencilUid uid = ref _currentState.DepthStencilUid;
-
- uid.DepthCompareFunction = depthTest.TestEnable ? depthTest.Func.Convert() : MTLCompareFunction.Always;
- uid.DepthWriteEnabled = depthTest.TestEnable && depthTest.WriteEnable;
-
- SignalDirty(DirtyFlags.DepthStencil);
- }
-
- public readonly void UpdateDepthClamp(bool clamp)
- {
- _currentState.DepthClipMode = clamp ? MTLDepthClipMode.Clamp : MTLDepthClipMode.Clip;
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetDepthClamp(renderCommandEncoder);
- return;
- }
-
- SignalDirty(DirtyFlags.DepthClamp);
- }
-
- public readonly void UpdateDepthBias(float depthBias, float slopeScale, float clamp)
- {
- _currentState.DepthBias = depthBias;
- _currentState.SlopeScale = slopeScale;
- _currentState.Clamp = clamp;
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetDepthBias(renderCommandEncoder);
- return;
- }
-
- SignalDirty(DirtyFlags.DepthBias);
- }
-
- public readonly void UpdateLogicOpState(bool enable, LogicalOp op)
- {
- _currentState.Pipeline.LogicOpEnable = enable;
- _currentState.Pipeline.LogicOp = op.Convert();
-
- SignalDirty(DirtyFlags.RenderPipeline);
- }
-
- public readonly void UpdateMultisampleState(MultisampleDescriptor multisample)
- {
- _currentState.Pipeline.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable;
- _currentState.Pipeline.AlphaToOneEnable = multisample.AlphaToOneEnable;
-
- SignalDirty(DirtyFlags.RenderPipeline);
- }
-
- public void UpdateScissors(ReadOnlySpan> regions)
- {
- for (int i = 0; i < regions.Length; i++)
- {
- Rectangle region = regions[i];
-
- _currentState.Scissors[i] = new MTLScissorRect
- {
- height = (ulong)region.Height,
- width = (ulong)region.Width,
- x = (ulong)region.X,
- y = (ulong)region.Y
- };
- }
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetScissors(renderCommandEncoder);
- return;
- }
-
- SignalDirty(DirtyFlags.Scissors);
- }
-
- public void UpdateViewports(ReadOnlySpan viewports)
- {
- static float Clamp(float value)
- {
- return Math.Clamp(value, 0f, 1f);
- }
-
- for (int i = 0; i < viewports.Length; i++)
- {
- Viewport viewport = viewports[i];
- // Y coordinate is inverted
- _currentState.Viewports[i] = new MTLViewport
- {
- originX = viewport.Region.X,
- originY = viewport.Region.Y + viewport.Region.Height,
- width = viewport.Region.Width,
- height = -viewport.Region.Height,
- znear = Clamp(viewport.DepthNear),
- zfar = Clamp(viewport.DepthFar)
- };
- }
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetViewports(renderCommandEncoder);
- return;
- }
-
- SignalDirty(DirtyFlags.Viewports);
- }
-
- public readonly void UpdateVertexBuffers(ReadOnlySpan vertexBuffers)
- {
- for (int i = 0; i < Constants.MaxVertexBuffers; i++)
- {
- if (i < vertexBuffers.Length)
- {
- VertexBufferDescriptor vertexBuffer = vertexBuffers[i];
-
- _currentState.VertexBuffers[i] = new VertexBufferState(
- vertexBuffer.Buffer.Handle,
- vertexBuffer.Buffer.Offset,
- vertexBuffer.Buffer.Size,
- vertexBuffer.Divisor,
- vertexBuffer.Stride);
- }
- else
- {
- _currentState.VertexBuffers[i] = VertexBufferState.Null;
- }
- }
-
- // Update the buffers on the pipeline
- UpdatePipelineVertexState(_currentState.VertexBuffers, _currentState.VertexAttribs);
-
- SignalDirty(DirtyFlags.RenderPipeline);
- }
-
- public readonly void UpdateUniformBuffers(ReadOnlySpan buffers)
- {
- foreach (BufferAssignment assignment in buffers)
- {
- BufferRange buffer = assignment.Range;
- int index = assignment.Binding;
-
- Auto mtlBuffer = buffer.Handle == BufferHandle.Null
- ? null
- : _bufferManager.GetBuffer(buffer.Handle, buffer.Write);
-
- _currentState.UniformBufferRefs[index] = new BufferRef(mtlBuffer, ref buffer);
- }
-
- SignalDirty(DirtyFlags.Uniforms);
- }
-
- public readonly void UpdateStorageBuffers(ReadOnlySpan buffers)
- {
- foreach (BufferAssignment assignment in buffers)
- {
- BufferRange buffer = assignment.Range;
- int index = assignment.Binding;
-
- Auto mtlBuffer = buffer.Handle == BufferHandle.Null
- ? null
- : _bufferManager.GetBuffer(buffer.Handle, buffer.Write);
-
- _currentState.StorageBufferRefs[index] = new BufferRef(mtlBuffer, ref buffer);
- }
-
- SignalDirty(DirtyFlags.Storages);
- }
-
- public readonly void UpdateStorageBuffers(int first, ReadOnlySpan> buffers)
- {
- for (int i = 0; i < buffers.Length; i++)
- {
- Auto mtlBuffer = buffers[i];
- int index = first + i;
-
- _currentState.StorageBufferRefs[index] = new BufferRef(mtlBuffer);
- }
-
- SignalDirty(DirtyFlags.Storages);
- }
-
- public void UpdateCullMode(bool enable, Face face)
- {
- bool dirtyScissor = (face == Face.FrontAndBack) != _currentState.CullBoth;
-
- _currentState.CullMode = enable ? face.Convert() : MTLCullMode.None;
- _currentState.CullBoth = face == Face.FrontAndBack;
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetCullMode(renderCommandEncoder);
- SetScissors(renderCommandEncoder);
- return;
- }
-
- // Mark dirty
- SignalDirty(DirtyFlags.CullMode);
-
- if (dirtyScissor)
- {
- SignalDirty(DirtyFlags.Scissors);
- }
- }
-
- public readonly void UpdateFrontFace(FrontFace frontFace)
- {
- _currentState.Winding = frontFace.Convert();
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetFrontFace(renderCommandEncoder);
- return;
- }
-
- SignalDirty(DirtyFlags.FrontFace);
- }
-
- private readonly void UpdateStencilRefValue(int frontRef, int backRef)
- {
- _currentState.FrontRefValue = frontRef;
- _currentState.BackRefValue = backRef;
-
- // Inline update
- if (_pipeline.Encoders.TryGetRenderEncoder(out MTLRenderCommandEncoder renderCommandEncoder))
- {
- SetStencilRefValue(renderCommandEncoder);
- }
-
- SignalDirty(DirtyFlags.StencilRef);
- }
-
- public readonly void UpdateTextureAndSampler(ShaderStage stage, int binding, TextureBase texture, SamplerHolder samplerHolder)
- {
- if (texture != null)
- {
- _currentState.TextureRefs[binding] = new(stage, texture, samplerHolder?.GetSampler());
- }
- else
- {
- _currentState.TextureRefs[binding] = default;
- }
-
- SignalDirty(DirtyFlags.Textures);
- }
-
- public readonly void UpdateImage(ShaderStage stage, int binding, TextureBase image)
- {
- if (image is Texture view)
- {
- _currentState.ImageRefs[binding] = new(stage, view);
- }
- else
- {
- _currentState.ImageRefs[binding] = default;
- }
-
- SignalDirty(DirtyFlags.Images);
- }
-
- public readonly void UpdateTextureArray(ShaderStage stage, int binding, TextureArray array)
- {
- ref EncoderState.ArrayRef arrayRef = ref GetArrayRef(ref _currentState.TextureArrayRefs, binding, ArrayGrowthSize);
-
- if (arrayRef.Stage != stage || arrayRef.Array != array)
- {
- arrayRef = new EncoderState.ArrayRef(stage, array);
-
- SignalDirty(DirtyFlags.Textures);
- }
- }
-
- public readonly void UpdateTextureArraySeparate(ShaderStage stage, int setIndex, TextureArray array)
- {
- ref EncoderState.ArrayRef arrayRef = ref GetArrayRef(ref _currentState.TextureArrayExtraRefs, setIndex - MetalRenderer.TotalSets);
-
- if (arrayRef.Stage != stage || arrayRef.Array != array)
- {
- arrayRef = new EncoderState.ArrayRef(stage, array);
-
- SignalDirty(DirtyFlags.Textures);
- }
- }
-
- public readonly void UpdateImageArray(ShaderStage stage, int binding, ImageArray array)
- {
- ref EncoderState.ArrayRef arrayRef = ref GetArrayRef(ref _currentState.ImageArrayRefs, binding, ArrayGrowthSize);
-
- if (arrayRef.Stage != stage || arrayRef.Array != array)
- {
- arrayRef = new EncoderState.ArrayRef(stage, array);
-
- SignalDirty(DirtyFlags.Images);
- }
- }
-
- public readonly void UpdateImageArraySeparate(ShaderStage stage, int setIndex, ImageArray array)
- {
- ref EncoderState.ArrayRef arrayRef = ref GetArrayRef(ref _currentState.ImageArrayExtraRefs, setIndex - MetalRenderer.TotalSets);
-
- if (arrayRef.Stage != stage || arrayRef.Array != array)
- {
- arrayRef = new EncoderState.ArrayRef(stage, array);
-
- SignalDirty(DirtyFlags.Images);
- }
- }
-
- private static ref EncoderState.ArrayRef GetArrayRef(ref EncoderState.ArrayRef[] array, int index, int growthSize = 1)
- {
- ArgumentOutOfRangeException.ThrowIfNegative(index);
-
- if (array.Length <= index)
- {
- Array.Resize(ref array, index + growthSize);
- }
-
- return ref array[index];
- }
-
- private readonly void SetDepthStencilState(MTLRenderCommandEncoder renderCommandEncoder)
- {
- if (DepthStencil != null)
- {
- MTLDepthStencilState state = _depthStencilCache.GetOrCreate(_currentState.DepthStencilUid);
-
- renderCommandEncoder.SetDepthStencilState(state);
- }
- else
- {
- renderCommandEncoder.SetDepthStencilState(_defaultState);
- }
- }
-
- private readonly void SetDepthClamp(MTLRenderCommandEncoder renderCommandEncoder)
- {
- renderCommandEncoder.SetDepthClipMode(_currentState.DepthClipMode);
- }
-
- private readonly void SetDepthBias(MTLRenderCommandEncoder renderCommandEncoder)
- {
- renderCommandEncoder.SetDepthBias(_currentState.DepthBias, _currentState.SlopeScale, _currentState.Clamp);
- }
-
- private unsafe void SetScissors(MTLRenderCommandEncoder renderCommandEncoder)
- {
- bool isTriangles = (_currentState.Topology == PrimitiveTopology.Triangles) ||
- (_currentState.Topology == PrimitiveTopology.TriangleStrip);
-
- if (_currentState.CullBoth && isTriangles)
- {
- renderCommandEncoder.SetScissorRect(new MTLScissorRect { x = 0, y = 0, width = 0, height = 0 });
- }
- else
- {
- if (_currentState.Scissors.Length > 0)
- {
- fixed (MTLScissorRect* pMtlScissors = _currentState.Scissors)
- {
- renderCommandEncoder.SetScissorRects((IntPtr)pMtlScissors, (ulong)_currentState.Scissors.Length);
- }
- }
- }
- }
-
- private readonly unsafe void SetViewports(MTLRenderCommandEncoder renderCommandEncoder)
- {
- if (_currentState.Viewports.Length > 0)
- {
- fixed (MTLViewport* pMtlViewports = _currentState.Viewports)
- {
- renderCommandEncoder.SetViewports((IntPtr)pMtlViewports, (ulong)_currentState.Viewports.Length);
- }
- }
- }
-
- private readonly void UpdatePipelineVertexState(VertexBufferState[] bufferDescriptors, VertexAttribDescriptor[] attribDescriptors)
- {
- ref PipelineState pipeline = ref _currentState.Pipeline;
- uint indexMask = 0;
-
- for (int i = 0; i < attribDescriptors.Length; i++)
- {
- ref VertexInputAttributeUid attrib = ref pipeline.Internal.VertexAttributes[i];
-
- if (attribDescriptors[i].IsZero)
- {
- attrib.Format = attribDescriptors[i].Format.Convert();
- indexMask |= 1u << (int)Constants.ZeroBufferIndex;
- attrib.BufferIndex = Constants.ZeroBufferIndex;
- attrib.Offset = 0;
- }
- else
- {
- attrib.Format = attribDescriptors[i].Format.Convert();
- indexMask |= 1u << attribDescriptors[i].BufferIndex;
- attrib.BufferIndex = (ulong)attribDescriptors[i].BufferIndex;
- attrib.Offset = (ulong)attribDescriptors[i].Offset;
- }
- }
-
- for (int i = 0; i < bufferDescriptors.Length; i++)
- {
- ref VertexInputLayoutUid layout = ref pipeline.Internal.VertexBindings[i];
-
- if ((indexMask & (1u << i)) != 0)
- {
- layout.Stride = (uint)bufferDescriptors[i].Stride;
-
- if (layout.Stride == 0)
- {
- layout.Stride = 1;
- layout.StepFunction = MTLVertexStepFunction.Constant;
- layout.StepRate = 0;
- }
- else
- {
- if (bufferDescriptors[i].Divisor > 0)
- {
- layout.StepFunction = MTLVertexStepFunction.PerInstance;
- layout.StepRate = (uint)bufferDescriptors[i].Divisor;
- }
- else
- {
- layout.StepFunction = MTLVertexStepFunction.PerVertex;
- layout.StepRate = 1;
- }
- }
- }
- else
- {
- layout = new();
- }
- }
-
- ref VertexInputLayoutUid zeroBufLayout = ref pipeline.Internal.VertexBindings[(int)Constants.ZeroBufferIndex];
-
- // Zero buffer
- if ((indexMask & (1u << (int)Constants.ZeroBufferIndex)) != 0)
- {
- zeroBufLayout.Stride = 1;
- zeroBufLayout.StepFunction = MTLVertexStepFunction.Constant;
- zeroBufLayout.StepRate = 0;
- }
- else
- {
- zeroBufLayout = new();
- }
-
- pipeline.VertexAttributeDescriptionsCount = (uint)attribDescriptors.Length;
- pipeline.VertexBindingDescriptionsCount = Constants.ZeroBufferIndex + 1; // TODO: move this out?
- }
-
- private readonly void SetVertexBuffers(VertexBufferState[] bufferStates, ref readonly RenderEncoderBindings bindings)
- {
- for (int i = 0; i < bufferStates.Length; i++)
- {
- (MTLBuffer mtlBuffer, int offset) = bufferStates[i].GetVertexBuffer(_bufferManager, _pipeline.Cbs);
-
- if (mtlBuffer.NativePtr != IntPtr.Zero)
- {
- bindings.VertexBuffers.Add(new BufferResource(mtlBuffer, (ulong)offset, (ulong)i));
- }
- }
-
- Auto autoZeroBuffer = _zeroBuffer == BufferHandle.Null
- ? null
- : _bufferManager.GetBuffer(_zeroBuffer, false);
-
- if (autoZeroBuffer == null)
- {
- return;
- }
-
- MTLBuffer zeroMtlBuffer = autoZeroBuffer.Get(_pipeline.Cbs).Value;
- bindings.VertexBuffers.Add(new BufferResource(zeroMtlBuffer, 0, Constants.ZeroBufferIndex));
- }
-
- private readonly (ulong gpuAddress, IntPtr nativePtr) AddressForBuffer(ref BufferRef buffer)
- {
- ulong gpuAddress = 0;
- IntPtr nativePtr = IntPtr.Zero;
-
- BufferRange? range = buffer.Range;
- Auto autoBuffer = buffer.Buffer;
-
- if (autoBuffer != null)
- {
- int offset = 0;
- MTLBuffer mtlBuffer;
-
- if (range.HasValue)
- {
- offset = range.Value.Offset;
- mtlBuffer = autoBuffer.Get(_pipeline.Cbs, offset, range.Value.Size, range.Value.Write).Value;
- }
- else
- {
- mtlBuffer = autoBuffer.Get(_pipeline.Cbs).Value;
- }
-
- gpuAddress = mtlBuffer.GpuAddress + (ulong)offset;
- nativePtr = mtlBuffer.NativePtr;
- }
-
- return (gpuAddress, nativePtr);
- }
-
- private readonly (ulong gpuAddress, IntPtr nativePtr) AddressForTexture(ref TextureRef texture)
- {
- TextureBase storage = texture.Storage;
-
- ulong gpuAddress = 0;
- IntPtr nativePtr = IntPtr.Zero;
-
- if (storage != null)
- {
- if (storage is TextureBuffer textureBuffer)
- {
- textureBuffer.RebuildStorage(false);
- }
-
- MTLTexture mtlTexture = storage.GetHandle();
-
- gpuAddress = mtlTexture.GpuResourceID._impl;
- nativePtr = mtlTexture.NativePtr;
- }
-
- return (gpuAddress, nativePtr);
- }
-
- private readonly (ulong gpuAddress, IntPtr nativePtr) AddressForImage(ref ImageRef image)
- {
- Texture storage = image.Storage;
-
- ulong gpuAddress = 0;
- IntPtr nativePtr = IntPtr.Zero;
-
- if (storage != null)
- {
- MTLTexture mtlTexture = storage.GetHandle();
-
- gpuAddress = mtlTexture.GpuResourceID._impl;
- nativePtr = mtlTexture.NativePtr;
- }
-
- return (gpuAddress, nativePtr);
- }
-
- private readonly (ulong gpuAddress, IntPtr nativePtr) AddressForTextureBuffer(ref TextureBuffer bufferTexture)
- {
- ulong gpuAddress = 0;
- IntPtr nativePtr = IntPtr.Zero;
-
- if (bufferTexture != null)
- {
- bufferTexture.RebuildStorage(false);
-
- MTLTexture mtlTexture = bufferTexture.GetHandle();
-
- gpuAddress = mtlTexture.GpuResourceID._impl;
- nativePtr = mtlTexture.NativePtr;
- }
-
- return (gpuAddress, nativePtr);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AddResource(IntPtr resourcePointer, MTLResourceUsage usage, MTLRenderStages stages, ref readonly RenderEncoderBindings bindings)
- {
- if (resourcePointer != IntPtr.Zero)
- {
- bindings.Resources.Add(new Resource(new MTLResource(resourcePointer), usage, stages));
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void AddResource(IntPtr resourcePointer, MTLResourceUsage usage, ref readonly ComputeEncoderBindings bindings)
- {
- if (resourcePointer != IntPtr.Zero)
- {
- bindings.Resources.Add(new Resource(new MTLResource(resourcePointer), usage, 0));
- }
- }
-
- private readonly void UpdateAndBind(Program program, uint setIndex, ref readonly RenderEncoderBindings bindings)
- {
- ResourceBindingSegment[] bindingSegments = program.BindingSegments[setIndex];
-
- if (bindingSegments.Length == 0)
- {
- return;
- }
-
- ScopedTemporaryBuffer vertArgBuffer = default;
- ScopedTemporaryBuffer fragArgBuffer = default;
-
- if (program.ArgumentBufferSizes[setIndex] > 0)
- {
- vertArgBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, program.ArgumentBufferSizes[setIndex] * sizeof(ulong));
- }
-
- if (program.FragArgumentBufferSizes[setIndex] > 0)
- {
- fragArgBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, program.FragArgumentBufferSizes[setIndex] * sizeof(ulong));
- }
-
- Span vertResourceIds = stackalloc ulong[program.ArgumentBufferSizes[setIndex]];
- Span fragResourceIds = stackalloc ulong[program.FragArgumentBufferSizes[setIndex]];
-
- int vertResourceIdIndex = 0;
- int fragResourceIdIndex = 0;
-
- foreach (ResourceBindingSegment segment in bindingSegments)
- {
- int binding = segment.Binding;
- int count = segment.Count;
-
- switch (setIndex)
- {
- case Constants.ConstantBuffersSetIndex:
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref BufferRef buffer = ref _currentState.UniformBufferRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForBuffer(ref buffer);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
- }
- break;
- case Constants.StorageBuffersSetIndex:
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref BufferRef buffer = ref _currentState.StorageBufferRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForBuffer(ref buffer);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
- }
- break;
- case Constants.TexturesSetIndex:
- if (!segment.IsArray)
- {
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref TextureRef texture = ref _currentState.TextureRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTexture(ref texture);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
-
- if (texture.Sampler != null)
- {
- vertResourceIds[vertResourceIdIndex] = texture.Sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl;
- vertResourceIdIndex++;
- }
-
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
-
- if (texture.Sampler != null)
- {
- fragResourceIds[fragResourceIdIndex] = texture.Sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl;
- fragResourceIdIndex++;
- }
-
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
- }
- }
- else
- {
- TextureArray textureArray = _currentState.TextureArrayRefs[binding].Array;
-
- if (segment.Type != ResourceType.BufferTexture)
- {
- TextureRef[] textures = textureArray.GetTextureRefs();
- Auto[] samplers = new Auto[textures.Length];
-
- for (int i = 0; i < textures.Length; i++)
- {
- TextureRef texture = textures[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTexture(ref texture);
-
- samplers[i] = texture.Sampler;
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
- }
-
- foreach (Auto sampler in samplers)
- {
- ulong gpuAddress = 0;
-
- if (sampler != null)
- {
- gpuAddress = sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl;
- }
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
- }
- }
- }
- else
- {
- TextureBuffer[] bufferTextures = textureArray.GetBufferTextureRefs();
-
- for (int i = 0; i < bufferTextures.Length; i++)
- {
- TextureBuffer bufferTexture = bufferTextures[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTextureBuffer(ref bufferTexture);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
-
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read, renderStages, in bindings);
- }
- }
- }
- break;
- case Constants.ImagesSetIndex:
- if (!segment.IsArray)
- {
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref ImageRef image = ref _currentState.ImageRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForImage(ref image);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages, in bindings);
- }
- }
- else
- {
- ImageArray imageArray = _currentState.ImageArrayRefs[binding].Array;
-
- if (segment.Type != ResourceType.BufferImage)
- {
- TextureRef[] images = imageArray.GetTextureRefs();
-
- for (int i = 0; i < images.Length; i++)
- {
- TextureRef image = images[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTexture(ref image);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages, in bindings);
- }
- }
- else
- {
- TextureBuffer[] bufferImages = imageArray.GetBufferTextureRefs();
-
- for (int i = 0; i < bufferImages.Length; i++)
- {
- TextureBuffer image = bufferImages[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTextureBuffer(ref image);
-
- MTLRenderStages renderStages = 0;
-
- if ((segment.Stages & ResourceStages.Vertex) != 0)
- {
- vertResourceIds[vertResourceIdIndex] = gpuAddress;
- vertResourceIdIndex++;
- renderStages |= MTLRenderStages.RenderStageVertex;
- }
-
- if ((segment.Stages & ResourceStages.Fragment) != 0)
- {
- fragResourceIds[fragResourceIdIndex] = gpuAddress;
- fragResourceIdIndex++;
- renderStages |= MTLRenderStages.RenderStageFragment;
- }
-
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, renderStages, in bindings);
- }
- }
- }
- break;
- }
- }
-
- if (program.ArgumentBufferSizes[setIndex] > 0)
- {
- vertArgBuffer.Holder.SetDataUnchecked(vertArgBuffer.Offset, MemoryMarshal.AsBytes(vertResourceIds));
- MTLBuffer mtlVertArgBuffer = _bufferManager.GetBuffer(vertArgBuffer.Handle, false).Get(_pipeline.Cbs).Value;
- bindings.VertexBuffers.Add(new BufferResource(mtlVertArgBuffer, (uint)vertArgBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
- }
-
- if (program.FragArgumentBufferSizes[setIndex] > 0)
- {
- fragArgBuffer.Holder.SetDataUnchecked(fragArgBuffer.Offset, MemoryMarshal.AsBytes(fragResourceIds));
- MTLBuffer mtlFragArgBuffer = _bufferManager.GetBuffer(fragArgBuffer.Handle, false).Get(_pipeline.Cbs).Value;
- bindings.FragmentBuffers.Add(new BufferResource(mtlFragArgBuffer, (uint)fragArgBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
- }
- }
-
- private readonly void UpdateAndBind(Program program, uint setIndex, ref readonly ComputeEncoderBindings bindings)
- {
- ResourceBindingSegment[] bindingSegments = program.BindingSegments[setIndex];
-
- if (bindingSegments.Length == 0)
- {
- return;
- }
-
- ScopedTemporaryBuffer argBuffer = default;
-
- if (program.ArgumentBufferSizes[setIndex] > 0)
- {
- argBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, program.ArgumentBufferSizes[setIndex] * sizeof(ulong));
- }
-
- Span resourceIds = stackalloc ulong[program.ArgumentBufferSizes[setIndex]];
- int resourceIdIndex = 0;
-
- foreach (ResourceBindingSegment segment in bindingSegments)
- {
- int binding = segment.Binding;
- int count = segment.Count;
-
- switch (setIndex)
- {
- case Constants.ConstantBuffersSetIndex:
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref BufferRef buffer = ref _currentState.UniformBufferRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForBuffer(ref buffer);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
- bindings.Resources.Add(new Resource(new MTLResource(nativePtr), MTLResourceUsage.Read, 0));
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
- }
- }
- break;
- case Constants.StorageBuffersSetIndex:
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref BufferRef buffer = ref _currentState.StorageBufferRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForBuffer(ref buffer);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
- }
- }
- break;
- case Constants.TexturesSetIndex:
- if (!segment.IsArray)
- {
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref TextureRef texture = ref _currentState.TextureRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTexture(ref texture);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
-
- if (texture.Sampler != null)
- {
- resourceIds[resourceIdIndex] = texture.Sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl;
- resourceIdIndex++;
- }
- }
- }
- }
- else
- {
- TextureArray textureArray = _currentState.TextureArrayRefs[binding].Array;
-
- if (segment.Type != ResourceType.BufferTexture)
- {
- TextureRef[] textures = textureArray.GetTextureRefs();
- Auto[] samplers = new Auto[textures.Length];
-
- for (int i = 0; i < textures.Length; i++)
- {
- TextureRef texture = textures[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTexture(ref texture);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
-
- samplers[i] = texture.Sampler;
- }
- }
-
- foreach (Auto sampler in samplers)
- {
- if (sampler != null)
- {
- resourceIds[resourceIdIndex] = sampler.Get(_pipeline.Cbs).Value.GpuResourceID._impl;
- resourceIdIndex++;
- }
- }
- }
- else
- {
- TextureBuffer[] bufferTextures = textureArray.GetBufferTextureRefs();
-
- for (int i = 0; i < bufferTextures.Length; i++)
- {
- TextureBuffer bufferTexture = bufferTextures[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTextureBuffer(ref bufferTexture);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
- }
- }
- }
- }
- break;
- case Constants.ImagesSetIndex:
- if (!segment.IsArray)
- {
- for (int i = 0; i < count; i++)
- {
- int index = binding + i;
-
- ref ImageRef image = ref _currentState.ImageRefs[index];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForImage(ref image);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
- }
- }
- }
- else
- {
- ImageArray imageArray = _currentState.ImageArrayRefs[binding].Array;
-
- if (segment.Type != ResourceType.BufferImage)
- {
- TextureRef[] images = imageArray.GetTextureRefs();
-
- for (int i = 0; i < images.Length; i++)
- {
- TextureRef image = images[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTexture(ref image);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
- }
- }
- }
- else
- {
- TextureBuffer[] bufferImages = imageArray.GetBufferTextureRefs();
-
- for (int i = 0; i < bufferImages.Length; i++)
- {
- TextureBuffer image = bufferImages[i];
- (ulong gpuAddress, IntPtr nativePtr) = AddressForTextureBuffer(ref image);
-
- if ((segment.Stages & ResourceStages.Compute) != 0)
- {
- AddResource(nativePtr, MTLResourceUsage.Read | MTLResourceUsage.Write, in bindings);
- resourceIds[resourceIdIndex] = gpuAddress;
- resourceIdIndex++;
- }
- }
- }
- }
- break;
- }
- }
-
- if (program.ArgumentBufferSizes[setIndex] > 0)
- {
- argBuffer.Holder.SetDataUnchecked(argBuffer.Offset, MemoryMarshal.AsBytes(resourceIds));
- MTLBuffer mtlArgBuffer = _bufferManager.GetBuffer(argBuffer.Handle, false).Get(_pipeline.Cbs).Value;
- bindings.Buffers.Add(new BufferResource(mtlArgBuffer, (uint)argBuffer.Range.Offset, SetIndexToBindingIndex(setIndex)));
- }
- }
-
- private static uint SetIndexToBindingIndex(uint setIndex)
- {
- return setIndex switch
- {
- Constants.ConstantBuffersSetIndex => Constants.ConstantBuffersIndex,
- Constants.StorageBuffersSetIndex => Constants.StorageBuffersIndex,
- Constants.TexturesSetIndex => Constants.TexturesIndex,
- Constants.ImagesSetIndex => Constants.ImagesIndex,
- _ => throw new NotImplementedException()
- };
- }
-
- private readonly void SetCullMode(MTLRenderCommandEncoder renderCommandEncoder)
- {
- renderCommandEncoder.SetCullMode(_currentState.CullMode);
- }
-
- private readonly void SetFrontFace(MTLRenderCommandEncoder renderCommandEncoder)
- {
- renderCommandEncoder.SetFrontFacingWinding(_currentState.Winding);
- }
-
- private readonly void SetStencilRefValue(MTLRenderCommandEncoder renderCommandEncoder)
- {
- renderCommandEncoder.SetStencilReferenceValues((uint)_currentState.FrontRefValue, (uint)_currentState.BackRefValue);
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/EnumConversion.cs b/src/Ryujinx.Graphics.Metal/EnumConversion.cs
deleted file mode 100644
index 7cfb5cbd4..000000000
--- a/src/Ryujinx.Graphics.Metal/EnumConversion.cs
+++ /dev/null
@@ -1,292 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- static class EnumConversion
- {
- public static MTLSamplerAddressMode Convert(this AddressMode mode)
- {
- return mode switch
- {
- AddressMode.Clamp => MTLSamplerAddressMode.ClampToEdge, // TODO: Should be clamp.
- AddressMode.Repeat => MTLSamplerAddressMode.Repeat,
- AddressMode.MirrorClamp => MTLSamplerAddressMode.MirrorClampToEdge, // TODO: Should be mirror clamp.
- AddressMode.MirroredRepeat => MTLSamplerAddressMode.MirrorRepeat,
- AddressMode.ClampToBorder => MTLSamplerAddressMode.ClampToBorderColor,
- AddressMode.ClampToEdge => MTLSamplerAddressMode.ClampToEdge,
- AddressMode.MirrorClampToEdge => MTLSamplerAddressMode.MirrorClampToEdge,
- AddressMode.MirrorClampToBorder => MTLSamplerAddressMode.ClampToBorderColor, // TODO: Should be mirror clamp to border.
- _ => LogInvalidAndReturn(mode, nameof(AddressMode), MTLSamplerAddressMode.ClampToEdge) // TODO: Should be clamp.
- };
- }
-
- public static MTLBlendFactor Convert(this BlendFactor factor)
- {
- return factor switch
- {
- BlendFactor.Zero or BlendFactor.ZeroGl => MTLBlendFactor.Zero,
- BlendFactor.One or BlendFactor.OneGl => MTLBlendFactor.One,
- BlendFactor.SrcColor or BlendFactor.SrcColorGl => MTLBlendFactor.SourceColor,
- BlendFactor.OneMinusSrcColor or BlendFactor.OneMinusSrcColorGl => MTLBlendFactor.OneMinusSourceColor,
- BlendFactor.SrcAlpha or BlendFactor.SrcAlphaGl => MTLBlendFactor.SourceAlpha,
- BlendFactor.OneMinusSrcAlpha or BlendFactor.OneMinusSrcAlphaGl => MTLBlendFactor.OneMinusSourceAlpha,
- BlendFactor.DstAlpha or BlendFactor.DstAlphaGl => MTLBlendFactor.DestinationAlpha,
- BlendFactor.OneMinusDstAlpha or BlendFactor.OneMinusDstAlphaGl => MTLBlendFactor.OneMinusDestinationAlpha,
- BlendFactor.DstColor or BlendFactor.DstColorGl => MTLBlendFactor.DestinationColor,
- BlendFactor.OneMinusDstColor or BlendFactor.OneMinusDstColorGl => MTLBlendFactor.OneMinusDestinationColor,
- BlendFactor.SrcAlphaSaturate or BlendFactor.SrcAlphaSaturateGl => MTLBlendFactor.SourceAlphaSaturated,
- BlendFactor.Src1Color or BlendFactor.Src1ColorGl => MTLBlendFactor.Source1Color,
- BlendFactor.OneMinusSrc1Color or BlendFactor.OneMinusSrc1ColorGl => MTLBlendFactor.OneMinusSource1Color,
- BlendFactor.Src1Alpha or BlendFactor.Src1AlphaGl => MTLBlendFactor.Source1Alpha,
- BlendFactor.OneMinusSrc1Alpha or BlendFactor.OneMinusSrc1AlphaGl => MTLBlendFactor.OneMinusSource1Alpha,
- BlendFactor.ConstantColor => MTLBlendFactor.BlendColor,
- BlendFactor.OneMinusConstantColor => MTLBlendFactor.OneMinusBlendColor,
- BlendFactor.ConstantAlpha => MTLBlendFactor.BlendAlpha,
- BlendFactor.OneMinusConstantAlpha => MTLBlendFactor.OneMinusBlendAlpha,
- _ => LogInvalidAndReturn(factor, nameof(BlendFactor), MTLBlendFactor.Zero)
- };
- }
-
- public static MTLBlendOperation Convert(this BlendOp op)
- {
- return op switch
- {
- BlendOp.Add or BlendOp.AddGl => MTLBlendOperation.Add,
- BlendOp.Subtract or BlendOp.SubtractGl => MTLBlendOperation.Subtract,
- BlendOp.ReverseSubtract or BlendOp.ReverseSubtractGl => MTLBlendOperation.ReverseSubtract,
- BlendOp.Minimum => MTLBlendOperation.Min,
- BlendOp.Maximum => MTLBlendOperation.Max,
- _ => LogInvalidAndReturn(op, nameof(BlendOp), MTLBlendOperation.Add)
- };
- }
-
- public static MTLCompareFunction Convert(this CompareOp op)
- {
- return op switch
- {
- CompareOp.Never or CompareOp.NeverGl => MTLCompareFunction.Never,
- CompareOp.Less or CompareOp.LessGl => MTLCompareFunction.Less,
- CompareOp.Equal or CompareOp.EqualGl => MTLCompareFunction.Equal,
- CompareOp.LessOrEqual or CompareOp.LessOrEqualGl => MTLCompareFunction.LessEqual,
- CompareOp.Greater or CompareOp.GreaterGl => MTLCompareFunction.Greater,
- CompareOp.NotEqual or CompareOp.NotEqualGl => MTLCompareFunction.NotEqual,
- CompareOp.GreaterOrEqual or CompareOp.GreaterOrEqualGl => MTLCompareFunction.GreaterEqual,
- CompareOp.Always or CompareOp.AlwaysGl => MTLCompareFunction.Always,
- _ => LogInvalidAndReturn(op, nameof(CompareOp), MTLCompareFunction.Never)
- };
- }
-
- public static MTLCullMode Convert(this Face face)
- {
- return face switch
- {
- Face.Back => MTLCullMode.Back,
- Face.Front => MTLCullMode.Front,
- Face.FrontAndBack => MTLCullMode.None,
- _ => LogInvalidAndReturn(face, nameof(Face), MTLCullMode.Back)
- };
- }
-
- public static MTLWinding Convert(this FrontFace frontFace)
- {
- // The viewport is flipped vertically, therefore we need to switch the winding order as well
- return frontFace switch
- {
- FrontFace.Clockwise => MTLWinding.CounterClockwise,
- FrontFace.CounterClockwise => MTLWinding.Clockwise,
- _ => LogInvalidAndReturn(frontFace, nameof(FrontFace), MTLWinding.Clockwise)
- };
- }
-
- public static MTLIndexType Convert(this IndexType type)
- {
- return type switch
- {
- IndexType.UShort => MTLIndexType.UInt16,
- IndexType.UInt => MTLIndexType.UInt32,
- _ => LogInvalidAndReturn(type, nameof(IndexType), MTLIndexType.UInt16)
- };
- }
-
- public static MTLLogicOperation Convert(this LogicalOp op)
- {
- return op switch
- {
- LogicalOp.Clear => MTLLogicOperation.Clear,
- LogicalOp.And => MTLLogicOperation.And,
- LogicalOp.AndReverse => MTLLogicOperation.AndReverse,
- LogicalOp.Copy => MTLLogicOperation.Copy,
- LogicalOp.AndInverted => MTLLogicOperation.AndInverted,
- LogicalOp.Noop => MTLLogicOperation.Noop,
- LogicalOp.Xor => MTLLogicOperation.Xor,
- LogicalOp.Or => MTLLogicOperation.Or,
- LogicalOp.Nor => MTLLogicOperation.Nor,
- LogicalOp.Equiv => MTLLogicOperation.Equivalence,
- LogicalOp.Invert => MTLLogicOperation.Invert,
- LogicalOp.OrReverse => MTLLogicOperation.OrReverse,
- LogicalOp.CopyInverted => MTLLogicOperation.CopyInverted,
- LogicalOp.OrInverted => MTLLogicOperation.OrInverted,
- LogicalOp.Nand => MTLLogicOperation.Nand,
- LogicalOp.Set => MTLLogicOperation.Set,
- _ => LogInvalidAndReturn(op, nameof(LogicalOp), MTLLogicOperation.And)
- };
- }
-
- public static MTLSamplerMinMagFilter Convert(this MagFilter filter)
- {
- return filter switch
- {
- MagFilter.Nearest => MTLSamplerMinMagFilter.Nearest,
- MagFilter.Linear => MTLSamplerMinMagFilter.Linear,
- _ => LogInvalidAndReturn(filter, nameof(MagFilter), MTLSamplerMinMagFilter.Nearest)
- };
- }
-
- public static (MTLSamplerMinMagFilter, MTLSamplerMipFilter) Convert(this MinFilter filter)
- {
- return filter switch
- {
- MinFilter.Nearest => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest),
- MinFilter.Linear => (MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear),
- MinFilter.NearestMipmapNearest => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest),
- MinFilter.LinearMipmapNearest => (MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Nearest),
- MinFilter.NearestMipmapLinear => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Linear),
- MinFilter.LinearMipmapLinear => (MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear),
- _ => LogInvalidAndReturn(filter, nameof(MinFilter), (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest))
-
- };
- }
-
- public static MTLPrimitiveType Convert(this PrimitiveTopology topology)
- {
- return topology switch
- {
- PrimitiveTopology.Points => MTLPrimitiveType.Point,
- PrimitiveTopology.Lines => MTLPrimitiveType.Line,
- PrimitiveTopology.LineStrip => MTLPrimitiveType.LineStrip,
- PrimitiveTopology.Triangles => MTLPrimitiveType.Triangle,
- PrimitiveTopology.TriangleStrip => MTLPrimitiveType.TriangleStrip,
- _ => LogInvalidAndReturn(topology, nameof(PrimitiveTopology), MTLPrimitiveType.Triangle)
- };
- }
-
- public static MTLStencilOperation Convert(this StencilOp op)
- {
- return op switch
- {
- StencilOp.Keep or StencilOp.KeepGl => MTLStencilOperation.Keep,
- StencilOp.Zero or StencilOp.ZeroGl => MTLStencilOperation.Zero,
- StencilOp.Replace or StencilOp.ReplaceGl => MTLStencilOperation.Replace,
- StencilOp.IncrementAndClamp or StencilOp.IncrementAndClampGl => MTLStencilOperation.IncrementClamp,
- StencilOp.DecrementAndClamp or StencilOp.DecrementAndClampGl => MTLStencilOperation.DecrementClamp,
- StencilOp.Invert or StencilOp.InvertGl => MTLStencilOperation.Invert,
- StencilOp.IncrementAndWrap or StencilOp.IncrementAndWrapGl => MTLStencilOperation.IncrementWrap,
- StencilOp.DecrementAndWrap or StencilOp.DecrementAndWrapGl => MTLStencilOperation.DecrementWrap,
- _ => LogInvalidAndReturn(op, nameof(StencilOp), MTLStencilOperation.Keep)
- };
- }
-
- public static MTLTextureType Convert(this Target target)
- {
- return target switch
- {
- Target.TextureBuffer => MTLTextureType.TextureBuffer,
- Target.Texture1D => MTLTextureType.Type1D,
- Target.Texture1DArray => MTLTextureType.Type1DArray,
- Target.Texture2D => MTLTextureType.Type2D,
- Target.Texture2DArray => MTLTextureType.Type2DArray,
- Target.Texture2DMultisample => MTLTextureType.Type2DMultisample,
- Target.Texture2DMultisampleArray => MTLTextureType.Type2DMultisampleArray,
- Target.Texture3D => MTLTextureType.Type3D,
- Target.Cubemap => MTLTextureType.Cube,
- Target.CubemapArray => MTLTextureType.CubeArray,
- _ => LogInvalidAndReturn(target, nameof(Target), MTLTextureType.Type2D)
- };
- }
-
- public static MTLTextureSwizzle Convert(this SwizzleComponent swizzleComponent)
- {
- return swizzleComponent switch
- {
- SwizzleComponent.Zero => MTLTextureSwizzle.Zero,
- SwizzleComponent.One => MTLTextureSwizzle.One,
- SwizzleComponent.Red => MTLTextureSwizzle.Red,
- SwizzleComponent.Green => MTLTextureSwizzle.Green,
- SwizzleComponent.Blue => MTLTextureSwizzle.Blue,
- SwizzleComponent.Alpha => MTLTextureSwizzle.Alpha,
- _ => LogInvalidAndReturn(swizzleComponent, nameof(SwizzleComponent), MTLTextureSwizzle.Zero)
- };
- }
-
- public static MTLVertexFormat Convert(this Format format)
- {
- return format switch
- {
- Format.R16Float => MTLVertexFormat.Half,
- Format.R16G16Float => MTLVertexFormat.Half2,
- Format.R16G16B16Float => MTLVertexFormat.Half3,
- Format.R16G16B16A16Float => MTLVertexFormat.Half4,
- Format.R32Float => MTLVertexFormat.Float,
- Format.R32G32Float => MTLVertexFormat.Float2,
- Format.R32G32B32Float => MTLVertexFormat.Float3,
- Format.R11G11B10Float => MTLVertexFormat.FloatRG11B10,
- Format.R32G32B32A32Float => MTLVertexFormat.Float4,
- Format.R8Uint => MTLVertexFormat.UChar,
- Format.R8G8Uint => MTLVertexFormat.UChar2,
- Format.R8G8B8Uint => MTLVertexFormat.UChar3,
- Format.R8G8B8A8Uint => MTLVertexFormat.UChar4,
- Format.R16Uint => MTLVertexFormat.UShort,
- Format.R16G16Uint => MTLVertexFormat.UShort2,
- Format.R16G16B16Uint => MTLVertexFormat.UShort3,
- Format.R16G16B16A16Uint => MTLVertexFormat.UShort4,
- Format.R32Uint => MTLVertexFormat.UInt,
- Format.R32G32Uint => MTLVertexFormat.UInt2,
- Format.R32G32B32Uint => MTLVertexFormat.UInt3,
- Format.R32G32B32A32Uint => MTLVertexFormat.UInt4,
- Format.R8Sint => MTLVertexFormat.Char,
- Format.R8G8Sint => MTLVertexFormat.Char2,
- Format.R8G8B8Sint => MTLVertexFormat.Char3,
- Format.R8G8B8A8Sint => MTLVertexFormat.Char4,
- Format.R16Sint => MTLVertexFormat.Short,
- Format.R16G16Sint => MTLVertexFormat.Short2,
- Format.R16G16B16Sint => MTLVertexFormat.Short3,
- Format.R16G16B16A16Sint => MTLVertexFormat.Short4,
- Format.R32Sint => MTLVertexFormat.Int,
- Format.R32G32Sint => MTLVertexFormat.Int2,
- Format.R32G32B32Sint => MTLVertexFormat.Int3,
- Format.R32G32B32A32Sint => MTLVertexFormat.Int4,
- Format.R8Unorm => MTLVertexFormat.UCharNormalized,
- Format.R8G8Unorm => MTLVertexFormat.UChar2Normalized,
- Format.R8G8B8Unorm => MTLVertexFormat.UChar3Normalized,
- Format.R8G8B8A8Unorm => MTLVertexFormat.UChar4Normalized,
- Format.R16Unorm => MTLVertexFormat.UShortNormalized,
- Format.R16G16Unorm => MTLVertexFormat.UShort2Normalized,
- Format.R16G16B16Unorm => MTLVertexFormat.UShort3Normalized,
- Format.R16G16B16A16Unorm => MTLVertexFormat.UShort4Normalized,
- Format.R10G10B10A2Unorm => MTLVertexFormat.UInt1010102Normalized,
- Format.R8Snorm => MTLVertexFormat.CharNormalized,
- Format.R8G8Snorm => MTLVertexFormat.Char2Normalized,
- Format.R8G8B8Snorm => MTLVertexFormat.Char3Normalized,
- Format.R8G8B8A8Snorm => MTLVertexFormat.Char4Normalized,
- Format.R16Snorm => MTLVertexFormat.ShortNormalized,
- Format.R16G16Snorm => MTLVertexFormat.Short2Normalized,
- Format.R16G16B16Snorm => MTLVertexFormat.Short3Normalized,
- Format.R16G16B16A16Snorm => MTLVertexFormat.Short4Normalized,
- Format.R10G10B10A2Snorm => MTLVertexFormat.Int1010102Normalized,
-
- _ => LogInvalidAndReturn(format, nameof(Format), MTLVertexFormat.Float4)
- };
- }
-
- private static T2 LogInvalidAndReturn(T1 value, string name, T2 defaultValue = default)
- {
- Logger.Debug?.Print(LogClass.Gpu, $"Invalid {name} enum value: {value}.");
-
- return defaultValue;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/FenceHolder.cs b/src/Ryujinx.Graphics.Metal/FenceHolder.cs
deleted file mode 100644
index a8dd28c0d..000000000
--- a/src/Ryujinx.Graphics.Metal/FenceHolder.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-using System.Threading;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class FenceHolder : IDisposable
- {
- private MTLCommandBuffer _fence;
- private int _referenceCount;
- private bool _disposed;
-
- public FenceHolder(MTLCommandBuffer fence)
- {
- _fence = fence;
- _referenceCount = 1;
- }
-
- public MTLCommandBuffer GetUnsafe()
- {
- return _fence;
- }
-
- public bool TryGet(out MTLCommandBuffer fence)
- {
- int lastValue;
- do
- {
- lastValue = _referenceCount;
-
- if (lastValue == 0)
- {
- fence = default;
- return false;
- }
- } while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
-
- fence = _fence;
- return true;
- }
-
- public MTLCommandBuffer Get()
- {
- Interlocked.Increment(ref _referenceCount);
- return _fence;
- }
-
- public void Put()
- {
- if (Interlocked.Decrement(ref _referenceCount) == 0)
- {
- _fence = default;
- }
- }
-
- public void Wait()
- {
- _fence.WaitUntilCompleted();
- }
-
- public bool IsSignaled()
- {
- return _fence.Status == MTLCommandBufferStatus.Completed;
- }
-
- public void Dispose()
- {
- if (!_disposed)
- {
- Put();
- _disposed = true;
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/FormatConverter.cs b/src/Ryujinx.Graphics.Metal/FormatConverter.cs
deleted file mode 100644
index e099187b8..000000000
--- a/src/Ryujinx.Graphics.Metal/FormatConverter.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Metal
-{
- class FormatConverter
- {
- public static void ConvertD24S8ToD32FS8(Span output, ReadOnlySpan input)
- {
- const float UnormToFloat = 1f / 0xffffff;
-
- Span outputUint = MemoryMarshal.Cast(output);
- ReadOnlySpan inputUint = MemoryMarshal.Cast(input);
-
- int i = 0;
-
- for (; i < inputUint.Length; i++)
- {
- uint depthStencil = inputUint[i];
- uint depth = depthStencil >> 8;
- uint stencil = depthStencil & 0xff;
-
- int j = i * 2;
-
- outputUint[j] = (uint)BitConverter.SingleToInt32Bits(depth * UnormToFloat);
- outputUint[j + 1] = stencil;
- }
- }
-
- public static void ConvertD32FS8ToD24S8(Span output, ReadOnlySpan input)
- {
- Span outputUint = MemoryMarshal.Cast(output);
- ReadOnlySpan inputUint = MemoryMarshal.Cast(input);
-
- int i = 0;
-
- for (; i < inputUint.Length; i += 2)
- {
- float depth = BitConverter.Int32BitsToSingle((int)inputUint[i]);
- uint stencil = inputUint[i + 1];
- uint depthStencil = (Math.Clamp((uint)(depth * 0xffffff), 0, 0xffffff) << 8) | (stencil & 0xff);
-
- int j = i >> 1;
-
- outputUint[j] = depthStencil;
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/FormatTable.cs b/src/Ryujinx.Graphics.Metal/FormatTable.cs
deleted file mode 100644
index 10c8b435c..000000000
--- a/src/Ryujinx.Graphics.Metal/FormatTable.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- static class FormatTable
- {
- private static readonly MTLPixelFormat[] _table;
-
- static FormatTable()
- {
- _table = new MTLPixelFormat[Enum.GetNames(typeof(Format)).Length];
-
- Add(Format.R8Unorm, MTLPixelFormat.R8Unorm);
- Add(Format.R8Snorm, MTLPixelFormat.R8Snorm);
- Add(Format.R8Uint, MTLPixelFormat.R8Uint);
- Add(Format.R8Sint, MTLPixelFormat.R8Sint);
- Add(Format.R16Float, MTLPixelFormat.R16Float);
- Add(Format.R16Unorm, MTLPixelFormat.R16Unorm);
- Add(Format.R16Snorm, MTLPixelFormat.R16Snorm);
- Add(Format.R16Uint, MTLPixelFormat.R16Uint);
- Add(Format.R16Sint, MTLPixelFormat.R16Sint);
- Add(Format.R32Float, MTLPixelFormat.R32Float);
- Add(Format.R32Uint, MTLPixelFormat.R32Uint);
- Add(Format.R32Sint, MTLPixelFormat.R32Sint);
- Add(Format.R8G8Unorm, MTLPixelFormat.RG8Unorm);
- Add(Format.R8G8Snorm, MTLPixelFormat.RG8Snorm);
- Add(Format.R8G8Uint, MTLPixelFormat.RG8Uint);
- Add(Format.R8G8Sint, MTLPixelFormat.RG8Sint);
- Add(Format.R16G16Float, MTLPixelFormat.RG16Float);
- Add(Format.R16G16Unorm, MTLPixelFormat.RG16Unorm);
- Add(Format.R16G16Snorm, MTLPixelFormat.RG16Snorm);
- Add(Format.R16G16Uint, MTLPixelFormat.RG16Uint);
- Add(Format.R16G16Sint, MTLPixelFormat.RG16Sint);
- Add(Format.R32G32Float, MTLPixelFormat.RG32Float);
- Add(Format.R32G32Uint, MTLPixelFormat.RG32Uint);
- Add(Format.R32G32Sint, MTLPixelFormat.RG32Sint);
- // Add(Format.R8G8B8Unorm, MTLPixelFormat.R8G8B8Unorm);
- // Add(Format.R8G8B8Snorm, MTLPixelFormat.R8G8B8Snorm);
- // Add(Format.R8G8B8Uint, MTLPixelFormat.R8G8B8Uint);
- // Add(Format.R8G8B8Sint, MTLPixelFormat.R8G8B8Sint);
- // Add(Format.R16G16B16Float, MTLPixelFormat.R16G16B16Float);
- // Add(Format.R16G16B16Unorm, MTLPixelFormat.R16G16B16Unorm);
- // Add(Format.R16G16B16Snorm, MTLPixelFormat.R16G16B16SNorm);
- // Add(Format.R16G16B16Uint, MTLPixelFormat.R16G16B16Uint);
- // Add(Format.R16G16B16Sint, MTLPixelFormat.R16G16B16Sint);
- // Add(Format.R32G32B32Float, MTLPixelFormat.R32G32B32Sfloat);
- // Add(Format.R32G32B32Uint, MTLPixelFormat.R32G32B32Uint);
- // Add(Format.R32G32B32Sint, MTLPixelFormat.R32G32B32Sint);
- Add(Format.R8G8B8A8Unorm, MTLPixelFormat.RGBA8Unorm);
- Add(Format.R8G8B8A8Snorm, MTLPixelFormat.RGBA8Snorm);
- Add(Format.R8G8B8A8Uint, MTLPixelFormat.RGBA8Uint);
- Add(Format.R8G8B8A8Sint, MTLPixelFormat.RGBA8Sint);
- Add(Format.R16G16B16A16Float, MTLPixelFormat.RGBA16Float);
- Add(Format.R16G16B16A16Unorm, MTLPixelFormat.RGBA16Unorm);
- Add(Format.R16G16B16A16Snorm, MTLPixelFormat.RGBA16Snorm);
- Add(Format.R16G16B16A16Uint, MTLPixelFormat.RGBA16Uint);
- Add(Format.R16G16B16A16Sint, MTLPixelFormat.RGBA16Sint);
- Add(Format.R32G32B32A32Float, MTLPixelFormat.RGBA32Float);
- Add(Format.R32G32B32A32Uint, MTLPixelFormat.RGBA32Uint);
- Add(Format.R32G32B32A32Sint, MTLPixelFormat.RGBA32Sint);
- Add(Format.S8Uint, MTLPixelFormat.Stencil8);
- Add(Format.D16Unorm, MTLPixelFormat.Depth16Unorm);
- Add(Format.S8UintD24Unorm, MTLPixelFormat.Depth24UnormStencil8);
- Add(Format.X8UintD24Unorm, MTLPixelFormat.Depth24UnormStencil8);
- Add(Format.D32Float, MTLPixelFormat.Depth32Float);
- Add(Format.D24UnormS8Uint, MTLPixelFormat.Depth24UnormStencil8);
- Add(Format.D32FloatS8Uint, MTLPixelFormat.Depth32FloatStencil8);
- Add(Format.R8G8B8A8Srgb, MTLPixelFormat.RGBA8UnormsRGB);
- // Add(Format.R4G4Unorm, MTLPixelFormat.R4G4Unorm);
- Add(Format.R4G4B4A4Unorm, MTLPixelFormat.RGBA8Unorm);
- // Add(Format.R5G5B5X1Unorm, MTLPixelFormat.R5G5B5X1Unorm);
- Add(Format.R5G5B5A1Unorm, MTLPixelFormat.BGR5A1Unorm);
- Add(Format.R5G6B5Unorm, MTLPixelFormat.B5G6R5Unorm);
- Add(Format.R10G10B10A2Unorm, MTLPixelFormat.RGB10A2Unorm);
- Add(Format.R10G10B10A2Uint, MTLPixelFormat.RGB10A2Uint);
- Add(Format.R11G11B10Float, MTLPixelFormat.RG11B10Float);
- Add(Format.R9G9B9E5Float, MTLPixelFormat.RGB9E5Float);
- Add(Format.Bc1RgbaUnorm, MTLPixelFormat.BC1RGBA);
- Add(Format.Bc2Unorm, MTLPixelFormat.BC2RGBA);
- Add(Format.Bc3Unorm, MTLPixelFormat.BC3RGBA);
- Add(Format.Bc1RgbaSrgb, MTLPixelFormat.BC1RGBAsRGB);
- Add(Format.Bc2Srgb, MTLPixelFormat.BC2RGBAsRGB);
- Add(Format.Bc3Srgb, MTLPixelFormat.BC3RGBAsRGB);
- Add(Format.Bc4Unorm, MTLPixelFormat.BC4RUnorm);
- Add(Format.Bc4Snorm, MTLPixelFormat.BC4RSnorm);
- Add(Format.Bc5Unorm, MTLPixelFormat.BC5RGUnorm);
- Add(Format.Bc5Snorm, MTLPixelFormat.BC5RGSnorm);
- Add(Format.Bc7Unorm, MTLPixelFormat.BC7RGBAUnorm);
- Add(Format.Bc7Srgb, MTLPixelFormat.BC7RGBAUnormsRGB);
- Add(Format.Bc6HSfloat, MTLPixelFormat.BC6HRGBFloat);
- Add(Format.Bc6HUfloat, MTLPixelFormat.BC6HRGBUfloat);
- Add(Format.Etc2RgbUnorm, MTLPixelFormat.ETC2RGB8);
- // Add(Format.Etc2RgbaUnorm, MTLPixelFormat.ETC2RGBA8);
- Add(Format.Etc2RgbPtaUnorm, MTLPixelFormat.ETC2RGB8A1);
- Add(Format.Etc2RgbSrgb, MTLPixelFormat.ETC2RGB8sRGB);
- // Add(Format.Etc2RgbaSrgb, MTLPixelFormat.ETC2RGBA8sRGB);
- Add(Format.Etc2RgbPtaSrgb, MTLPixelFormat.ETC2RGB8A1sRGB);
- // Add(Format.R8Uscaled, MTLPixelFormat.R8Uscaled);
- // Add(Format.R8Sscaled, MTLPixelFormat.R8Sscaled);
- // Add(Format.R16Uscaled, MTLPixelFormat.R16Uscaled);
- // Add(Format.R16Sscaled, MTLPixelFormat.R16Sscaled);
- // Add(Format.R32Uscaled, MTLPixelFormat.R32Uscaled);
- // Add(Format.R32Sscaled, MTLPixelFormat.R32Sscaled);
- // Add(Format.R8G8Uscaled, MTLPixelFormat.R8G8Uscaled);
- // Add(Format.R8G8Sscaled, MTLPixelFormat.R8G8Sscaled);
- // Add(Format.R16G16Uscaled, MTLPixelFormat.R16G16Uscaled);
- // Add(Format.R16G16Sscaled, MTLPixelFormat.R16G16Sscaled);
- // Add(Format.R32G32Uscaled, MTLPixelFormat.R32G32Uscaled);
- // Add(Format.R32G32Sscaled, MTLPixelFormat.R32G32Sscaled);
- // Add(Format.R8G8B8Uscaled, MTLPixelFormat.R8G8B8Uscaled);
- // Add(Format.R8G8B8Sscaled, MTLPixelFormat.R8G8B8Sscaled);
- // Add(Format.R16G16B16Uscaled, MTLPixelFormat.R16G16B16Uscaled);
- // Add(Format.R16G16B16Sscaled, MTLPixelFormat.R16G16B16Sscaled);
- // Add(Format.R32G32B32Uscaled, MTLPixelFormat.R32G32B32Uscaled);
- // Add(Format.R32G32B32Sscaled, MTLPixelFormat.R32G32B32Sscaled);
- // Add(Format.R8G8B8A8Uscaled, MTLPixelFormat.R8G8B8A8Uscaled);
- // Add(Format.R8G8B8A8Sscaled, MTLPixelFormat.R8G8B8A8Sscaled);
- // Add(Format.R16G16B16A16Uscaled, MTLPixelFormat.R16G16B16A16Uscaled);
- // Add(Format.R16G16B16A16Sscaled, MTLPixelFormat.R16G16B16A16Sscaled);
- // Add(Format.R32G32B32A32Uscaled, MTLPixelFormat.R32G32B32A32Uscaled);
- // Add(Format.R32G32B32A32Sscaled, MTLPixelFormat.R32G32B32A32Sscaled);
- // Add(Format.R10G10B10A2Snorm, MTLPixelFormat.A2B10G10R10SNormPack32);
- // Add(Format.R10G10B10A2Sint, MTLPixelFormat.A2B10G10R10SintPack32);
- // Add(Format.R10G10B10A2Uscaled, MTLPixelFormat.A2B10G10R10UscaledPack32);
- // Add(Format.R10G10B10A2Sscaled, MTLPixelFormat.A2B10G10R10SscaledPack32);
- Add(Format.Astc4x4Unorm, MTLPixelFormat.ASTC4x4LDR);
- Add(Format.Astc5x4Unorm, MTLPixelFormat.ASTC5x4LDR);
- Add(Format.Astc5x5Unorm, MTLPixelFormat.ASTC5x5LDR);
- Add(Format.Astc6x5Unorm, MTLPixelFormat.ASTC6x5LDR);
- Add(Format.Astc6x6Unorm, MTLPixelFormat.ASTC6x6LDR);
- Add(Format.Astc8x5Unorm, MTLPixelFormat.ASTC8x5LDR);
- Add(Format.Astc8x6Unorm, MTLPixelFormat.ASTC8x6LDR);
- Add(Format.Astc8x8Unorm, MTLPixelFormat.ASTC8x8LDR);
- Add(Format.Astc10x5Unorm, MTLPixelFormat.ASTC10x5LDR);
- Add(Format.Astc10x6Unorm, MTLPixelFormat.ASTC10x6LDR);
- Add(Format.Astc10x8Unorm, MTLPixelFormat.ASTC10x8LDR);
- Add(Format.Astc10x10Unorm, MTLPixelFormat.ASTC10x10LDR);
- Add(Format.Astc12x10Unorm, MTLPixelFormat.ASTC12x10LDR);
- Add(Format.Astc12x12Unorm, MTLPixelFormat.ASTC12x12LDR);
- Add(Format.Astc4x4Srgb, MTLPixelFormat.ASTC4x4sRGB);
- Add(Format.Astc5x4Srgb, MTLPixelFormat.ASTC5x4sRGB);
- Add(Format.Astc5x5Srgb, MTLPixelFormat.ASTC5x5sRGB);
- Add(Format.Astc6x5Srgb, MTLPixelFormat.ASTC6x5sRGB);
- Add(Format.Astc6x6Srgb, MTLPixelFormat.ASTC6x6sRGB);
- Add(Format.Astc8x5Srgb, MTLPixelFormat.ASTC8x5sRGB);
- Add(Format.Astc8x6Srgb, MTLPixelFormat.ASTC8x6sRGB);
- Add(Format.Astc8x8Srgb, MTLPixelFormat.ASTC8x8sRGB);
- Add(Format.Astc10x5Srgb, MTLPixelFormat.ASTC10x5sRGB);
- Add(Format.Astc10x6Srgb, MTLPixelFormat.ASTC10x6sRGB);
- Add(Format.Astc10x8Srgb, MTLPixelFormat.ASTC10x8sRGB);
- Add(Format.Astc10x10Srgb, MTLPixelFormat.ASTC10x10sRGB);
- Add(Format.Astc12x10Srgb, MTLPixelFormat.ASTC12x10sRGB);
- Add(Format.Astc12x12Srgb, MTLPixelFormat.ASTC12x12sRGB);
- Add(Format.B5G6R5Unorm, MTLPixelFormat.B5G6R5Unorm);
- Add(Format.B5G5R5A1Unorm, MTLPixelFormat.BGR5A1Unorm);
- Add(Format.A1B5G5R5Unorm, MTLPixelFormat.A1BGR5Unorm);
- Add(Format.B8G8R8A8Unorm, MTLPixelFormat.BGRA8Unorm);
- Add(Format.B8G8R8A8Srgb, MTLPixelFormat.BGRA8UnormsRGB);
- }
-
- private static void Add(Format format, MTLPixelFormat mtlFormat)
- {
- _table[(int)format] = mtlFormat;
- }
-
- public static MTLPixelFormat GetFormat(Format format)
- {
- MTLPixelFormat mtlFormat = _table[(int)format];
-
- if (IsD24S8(format))
- {
- if (!MTLDevice.CreateSystemDefaultDevice().Depth24Stencil8PixelFormatSupported)
- {
- mtlFormat = MTLPixelFormat.Depth32FloatStencil8;
- }
- }
-
- if (mtlFormat == MTLPixelFormat.Invalid)
- {
- Logger.Error?.PrintMsg(LogClass.Gpu, $"Format {format} is not supported by the host.");
- }
-
- return mtlFormat;
- }
-
- public static bool IsD24S8(Format format)
- {
- return format == Format.D24UnormS8Uint || format == Format.S8UintD24Unorm || format == Format.X8UintD24Unorm;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/HardwareInfo.cs b/src/Ryujinx.Graphics.Metal/HardwareInfo.cs
deleted file mode 100644
index f6a132f09..000000000
--- a/src/Ryujinx.Graphics.Metal/HardwareInfo.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Metal
-{
- static partial class HardwareInfoTools
- {
-
- private readonly static IntPtr _kCFAllocatorDefault = IntPtr.Zero;
- private readonly static UInt32 _kCFStringEncodingASCII = 0x0600;
- private const string IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit";
- private const string CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
-
- [LibraryImport(IOKit, StringMarshalling = StringMarshalling.Utf8)]
- private static partial IntPtr IOServiceMatching(string name);
-
- [LibraryImport(IOKit)]
- private static partial IntPtr IOServiceGetMatchingService(IntPtr mainPort, IntPtr matching);
-
- [LibraryImport(IOKit)]
- private static partial IntPtr IORegistryEntryCreateCFProperty(IntPtr entry, IntPtr key, IntPtr allocator, UInt32 options);
-
- [LibraryImport(CoreFoundation, StringMarshalling = StringMarshalling.Utf8)]
- private static partial IntPtr CFStringCreateWithCString(IntPtr allocator, string cString, UInt32 encoding);
-
- [LibraryImport(CoreFoundation)]
- [return: MarshalAs(UnmanagedType.U1)]
- public static partial bool CFStringGetCString(IntPtr theString, IntPtr buffer, long bufferSizes, UInt32 encoding);
-
- [LibraryImport(CoreFoundation)]
- public static partial IntPtr CFDataGetBytePtr(IntPtr theData);
-
- static string GetNameFromId(uint id)
- {
- return id switch
- {
- 0x1002 => "AMD",
- 0x106B => "Apple",
- 0x10DE => "NVIDIA",
- 0x13B5 => "ARM",
- 0x8086 => "Intel",
- _ => $"0x{id:X}"
- };
- }
-
- public static string GetVendor()
- {
- IntPtr serviceDict = IOServiceMatching("IOGPU");
- IntPtr service = IOServiceGetMatchingService(IntPtr.Zero, serviceDict);
- IntPtr cfString = CFStringCreateWithCString(_kCFAllocatorDefault, "vendor-id", _kCFStringEncodingASCII);
- IntPtr cfProperty = IORegistryEntryCreateCFProperty(service, cfString, _kCFAllocatorDefault, 0);
-
- byte[] buffer = new byte[4];
- IntPtr bufferPtr = CFDataGetBytePtr(cfProperty);
- Marshal.Copy(bufferPtr, buffer, 0, buffer.Length);
-
- uint vendorId = BitConverter.ToUInt32(buffer);
-
- return GetNameFromId(vendorId);
- }
-
- public static string GetModel()
- {
- IntPtr serviceDict = IOServiceMatching("IOGPU");
- IntPtr service = IOServiceGetMatchingService(IntPtr.Zero, serviceDict);
- IntPtr cfString = CFStringCreateWithCString(_kCFAllocatorDefault, "model", _kCFStringEncodingASCII);
- IntPtr cfProperty = IORegistryEntryCreateCFProperty(service, cfString, _kCFAllocatorDefault, 0);
-
- char[] buffer = new char[64];
- IntPtr bufferPtr = Marshal.AllocHGlobal(buffer.Length);
-
- if (CFStringGetCString(cfProperty, bufferPtr, buffer.Length, _kCFStringEncodingASCII))
- {
- string model = Marshal.PtrToStringUTF8(bufferPtr);
- Marshal.FreeHGlobal(bufferPtr);
- return model;
- }
-
- return string.Empty;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/HashTableSlim.cs b/src/Ryujinx.Graphics.Metal/HashTableSlim.cs
deleted file mode 100644
index 267acc6f4..000000000
--- a/src/Ryujinx.Graphics.Metal/HashTableSlim.cs
+++ /dev/null
@@ -1,143 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
-
-namespace Ryujinx.Graphics.Metal
-{
- interface IRefEquatable
- {
- bool Equals(ref T other);
- }
-
- class HashTableSlim where TKey : IRefEquatable
- {
- private const int TotalBuckets = 16; // Must be power of 2
- private const int TotalBucketsMask = TotalBuckets - 1;
-
- private struct Entry
- {
- public int Hash;
- public TKey Key;
- public TValue Value;
- }
-
- private struct Bucket
- {
- public int Length;
- public Entry[] Entries;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly Span AsSpan()
- {
- return Entries == null ? Span.Empty : Entries.AsSpan(0, Length);
- }
- }
-
- private readonly Bucket[] _hashTable = new Bucket[TotalBuckets];
-
- public IEnumerable Keys
- {
- get
- {
- foreach (Bucket bucket in _hashTable)
- {
- for (int i = 0; i < bucket.Length; i++)
- {
- yield return bucket.Entries[i].Key;
- }
- }
- }
- }
-
- public IEnumerable Values
- {
- get
- {
- foreach (Bucket bucket in _hashTable)
- {
- for (int i = 0; i < bucket.Length; i++)
- {
- yield return bucket.Entries[i].Value;
- }
- }
- }
- }
-
- public void Add(ref TKey key, TValue value)
- {
- Entry entry = new()
- {
- Hash = key.GetHashCode(),
- Key = key,
- Value = value,
- };
-
- int hashCode = key.GetHashCode();
- int bucketIndex = hashCode & TotalBucketsMask;
-
- ref Bucket bucket = ref _hashTable[bucketIndex];
- if (bucket.Entries != null)
- {
- int index = bucket.Length;
-
- if (index >= bucket.Entries.Length)
- {
- Array.Resize(ref bucket.Entries, index + 1);
- }
-
- bucket.Entries[index] = entry;
- }
- else
- {
- bucket.Entries =
- [
- entry
- ];
- }
-
- bucket.Length++;
- }
-
- public bool Remove(ref TKey key)
- {
- int hashCode = key.GetHashCode();
-
- ref Bucket bucket = ref _hashTable[hashCode & TotalBucketsMask];
- Span entries = bucket.AsSpan();
- for (int i = 0; i < entries.Length; i++)
- {
- ref Entry entry = ref entries[i];
-
- if (entry.Hash == hashCode && entry.Key.Equals(ref key))
- {
- entries[(i + 1)..].CopyTo(entries[i..]);
- bucket.Length--;
-
- return true;
- }
- }
-
- return false;
- }
-
- public bool TryGetValue(ref TKey key, out TValue value)
- {
- int hashCode = key.GetHashCode();
-
- Span entries = _hashTable[hashCode & TotalBucketsMask].AsSpan();
- for (int i = 0; i < entries.Length; i++)
- {
- ref Entry entry = ref entries[i];
-
- if (entry.Hash == hashCode && entry.Key.Equals(ref key))
- {
- value = entry.Value;
- return true;
- }
- }
-
- value = default;
- return false;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/HelperShader.cs b/src/Ryujinx.Graphics.Metal/HelperShader.cs
deleted file mode 100644
index 2638a6eac..000000000
--- a/src/Ryujinx.Graphics.Metal/HelperShader.cs
+++ /dev/null
@@ -1,868 +0,0 @@
-using Ryujinx.Common;
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader;
-using Ryujinx.Graphics.Shader.Translation;
-using SharpMetal.Metal;
-using System;
-using System.Collections.Generic;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class HelperShader : IDisposable
- {
- private const int ConvertElementsPerWorkgroup = 32 * 100; // Work group size of 32 times 100 elements.
- private const string ShadersSourcePath = "/Ryujinx.Graphics.Metal/Shaders";
- private readonly MetalRenderer _renderer;
- private readonly Pipeline _pipeline;
- private MTLDevice _device;
-
- private readonly ISampler _samplerLinear;
- private readonly ISampler _samplerNearest;
- private readonly IProgram _programColorBlitF;
- private readonly IProgram _programColorBlitI;
- private readonly IProgram _programColorBlitU;
- private readonly IProgram _programColorBlitMsF;
- private readonly IProgram _programColorBlitMsI;
- private readonly IProgram _programColorBlitMsU;
- private readonly List _programsColorClearF = [];
- private readonly List _programsColorClearI = [];
- private readonly List _programsColorClearU = [];
- private readonly IProgram _programDepthStencilClear;
- private readonly IProgram _programStrideChange;
- private readonly IProgram _programConvertD32S8ToD24S8;
- private readonly IProgram _programConvertIndexBuffer;
- private readonly IProgram _programDepthBlit;
- private readonly IProgram _programDepthBlitMs;
- private readonly IProgram _programStencilBlit;
- private readonly IProgram _programStencilBlitMs;
-
- private readonly EncoderState _helperShaderState = new();
-
- public HelperShader(MTLDevice device, MetalRenderer renderer, Pipeline pipeline)
- {
- _device = device;
- _renderer = renderer;
- _pipeline = pipeline;
-
- _samplerNearest = new SamplerHolder(renderer, _device, SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
- _samplerLinear = new SamplerHolder(renderer, _device, SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
-
- ResourceLayout blitResourceLayout = new ResourceLayoutBuilder()
- .Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 0)
- .Add(ResourceStages.Fragment, ResourceType.TextureAndSampler, 0).Build();
-
- string blitSource = ReadMsl("Blit.metal");
-
- string blitSourceF = blitSource.Replace("FORMAT", "float", StringComparison.Ordinal);
- _programColorBlitF = new Program(renderer, device, [
- new ShaderSource(blitSourceF, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string blitSourceI = blitSource.Replace("FORMAT", "int");
- _programColorBlitI = new Program(renderer, device, [
- new ShaderSource(blitSourceI, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceI, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string blitSourceU = blitSource.Replace("FORMAT", "uint");
- _programColorBlitU = new Program(renderer, device, [
- new ShaderSource(blitSourceU, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceU, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string blitMsSource = ReadMsl("BlitMs.metal");
-
- string blitMsSourceF = blitMsSource.Replace("FORMAT", "float");
- _programColorBlitMsF = new Program(renderer, device, [
- new ShaderSource(blitMsSourceF, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitMsSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string blitMsSourceI = blitMsSource.Replace("FORMAT", "int");
- _programColorBlitMsI = new Program(renderer, device, [
- new ShaderSource(blitMsSourceI, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitMsSourceI, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string blitMsSourceU = blitMsSource.Replace("FORMAT", "uint");
- _programColorBlitMsU = new Program(renderer, device, [
- new ShaderSource(blitMsSourceU, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitMsSourceU, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- ResourceLayout colorClearResourceLayout = new ResourceLayoutBuilder()
- .Add(ResourceStages.Fragment, ResourceType.UniformBuffer, 0).Build();
-
- string colorClearSource = ReadMsl("ColorClear.metal");
-
- for (int i = 0; i < Constants.MaxColorAttachments; i++)
- {
- string crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "float");
- _programsColorClearF.Add(new Program(renderer, device, [
- new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
- ], colorClearResourceLayout));
- }
-
- for (int i = 0; i < Constants.MaxColorAttachments; i++)
- {
- string crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "int");
- _programsColorClearI.Add(new Program(renderer, device, [
- new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
- ], colorClearResourceLayout));
- }
-
- for (int i = 0; i < Constants.MaxColorAttachments; i++)
- {
- string crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "uint");
- _programsColorClearU.Add(new Program(renderer, device, [
- new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
- ], colorClearResourceLayout));
- }
-
- string depthStencilClearSource = ReadMsl("DepthStencilClear.metal");
- _programDepthStencilClear = new Program(renderer, device, [
- new ShaderSource(depthStencilClearSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(depthStencilClearSource, ShaderStage.Vertex, TargetLanguage.Msl)
- ], colorClearResourceLayout);
-
- ResourceLayout strideChangeResourceLayout = new ResourceLayoutBuilder()
- .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0)
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build();
-
- string strideChangeSource = ReadMsl("ChangeBufferStride.metal");
- _programStrideChange = new Program(renderer, device, [
- new ShaderSource(strideChangeSource, ShaderStage.Compute, TargetLanguage.Msl)
- ], strideChangeResourceLayout, new ComputeSize(64, 1, 1));
-
- ResourceLayout convertD32S8ToD24S8ResourceLayout = new ResourceLayoutBuilder()
- .Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0)
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build();
-
- string convertD32S8ToD24S8Source = ReadMsl("ConvertD32S8ToD24S8.metal");
- _programConvertD32S8ToD24S8 = new Program(renderer, device, [
- new ShaderSource(convertD32S8ToD24S8Source, ShaderStage.Compute, TargetLanguage.Msl)
- ], convertD32S8ToD24S8ResourceLayout, new ComputeSize(64, 1, 1));
-
- ResourceLayout convertIndexBufferLayout = new ResourceLayoutBuilder()
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true)
- .Add(ResourceStages.Compute, ResourceType.StorageBuffer, 3).Build();
-
- string convertIndexBufferSource = ReadMsl("ConvertIndexBuffer.metal");
- _programConvertIndexBuffer = new Program(renderer, device, [
- new ShaderSource(convertIndexBufferSource, ShaderStage.Compute, TargetLanguage.Msl)
- ], convertIndexBufferLayout, new ComputeSize(16, 1, 1));
-
- string depthBlitSource = ReadMsl("DepthBlit.metal");
- _programDepthBlit = new Program(renderer, device, [
- new ShaderSource(depthBlitSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string depthBlitMsSource = ReadMsl("DepthBlitMs.metal");
- _programDepthBlitMs = new Program(renderer, device, [
- new ShaderSource(depthBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string stencilBlitSource = ReadMsl("StencilBlit.metal");
- _programStencilBlit = new Program(renderer, device, [
- new ShaderSource(stencilBlitSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
-
- string stencilBlitMsSource = ReadMsl("StencilBlitMs.metal");
- _programStencilBlitMs = new Program(renderer, device, [
- new ShaderSource(stencilBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
- new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
- ], blitResourceLayout);
- }
-
- private static string ReadMsl(string fileName)
- {
- string msl = EmbeddedResources.ReadAllText(string.Join('/', ShadersSourcePath, fileName));
-
-#pragma warning disable IDE0055 // Disable formatting
- msl = msl.Replace("CONSTANT_BUFFERS_INDEX", $"{Constants.ConstantBuffersIndex}")
- .Replace("STORAGE_BUFFERS_INDEX", $"{Constants.StorageBuffersIndex}")
- .Replace("TEXTURES_INDEX", $"{Constants.TexturesIndex}")
- .Replace("IMAGES_INDEX", $"{Constants.ImagesIndex}");
-#pragma warning restore IDE0055
-
- return msl;
- }
-
- public unsafe void BlitColor(
- CommandBufferScoped cbs,
- Texture src,
- Texture dst,
- Extents2D srcRegion,
- Extents2D dstRegion,
- bool linearFilter,
- bool clear = false)
- {
- _pipeline.SwapState(_helperShaderState);
-
- const int RegionBufferSize = 16;
-
- ISampler sampler = linearFilter ? _samplerLinear : _samplerNearest;
-
- _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
-
- Span region = stackalloc float[RegionBufferSize / sizeof(float)];
-
- region[0] = srcRegion.X1 / (float)src.Width;
- region[1] = srcRegion.X2 / (float)src.Width;
- region[2] = srcRegion.Y1 / (float)src.Height;
- region[3] = srcRegion.Y2 / (float)src.Height;
-
- if (dstRegion.X1 > dstRegion.X2)
- {
- (region[0], region[1]) = (region[1], region[0]);
- }
-
- if (dstRegion.Y1 > dstRegion.Y2)
- {
- (region[2], region[3]) = (region[3], region[2]);
- }
-
- using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, RegionBufferSize);
- buffer.Holder.SetDataUnchecked(buffer.Offset, region);
- _pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
-
- Rectangle rect = new(
- MathF.Min(dstRegion.X1, dstRegion.X2),
- MathF.Min(dstRegion.Y1, dstRegion.Y2),
- MathF.Abs(dstRegion.X2 - dstRegion.X1),
- MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
-
- Span viewports = stackalloc Viewport[16];
-
- viewports[0] = new Viewport(
- rect,
- ViewportSwizzle.PositiveX,
- ViewportSwizzle.PositiveY,
- ViewportSwizzle.PositiveZ,
- ViewportSwizzle.PositiveW,
- 0f,
- 1f);
-
- bool dstIsDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
-
- if (dstIsDepthOrStencil)
- {
- // TODO: Depth & stencil blit!
- Logger.Warning?.PrintMsg(LogClass.Gpu, "Requested a depth or stencil blit!");
- _pipeline.SwapState(null);
- return;
- }
-
- string debugGroupName = "Blit Color ";
-
- if (src.Info.Target.IsMultisample())
- {
- if (dst.Info.Format.IsSint())
- {
- debugGroupName += "MS Int";
- _pipeline.SetProgram(_programColorBlitMsI);
- }
- else if (dst.Info.Format.IsUint())
- {
- debugGroupName += "MS UInt";
- _pipeline.SetProgram(_programColorBlitMsU);
- }
- else
- {
- debugGroupName += "MS Float";
- _pipeline.SetProgram(_programColorBlitMsF);
- }
- }
- else
- {
- if (dst.Info.Format.IsSint())
- {
- debugGroupName += "Int";
- _pipeline.SetProgram(_programColorBlitI);
- }
- else if (dst.Info.Format.IsUint())
- {
- debugGroupName += "UInt";
- _pipeline.SetProgram(_programColorBlitU);
- }
- else
- {
- debugGroupName += "Float";
- _pipeline.SetProgram(_programColorBlitF);
- }
- }
-
- int dstWidth = dst.Width;
- int dstHeight = dst.Height;
-
- Span> scissors = stackalloc Rectangle[16];
-
- scissors[0] = new Rectangle(0, 0, dstWidth, dstHeight);
-
- _pipeline.SetRenderTargets([dst], null);
- _pipeline.SetScissors(scissors);
-
- _pipeline.SetClearLoadAction(clear);
-
- _pipeline.SetViewports(viewports);
- _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
- _pipeline.Draw(4, 1, 0, 0, debugGroupName);
-
- // Cleanup
- if (clear)
- {
- _pipeline.SetClearLoadAction(false);
- }
-
- // Restore previous state
- _pipeline.SwapState(null);
- }
-
- public unsafe void BlitDepthStencil(
- CommandBufferScoped cbs,
- Texture src,
- Texture dst,
- Extents2D srcRegion,
- Extents2D dstRegion)
- {
- _pipeline.SwapState(_helperShaderState);
-
- const int RegionBufferSize = 16;
-
- Span region = stackalloc float[RegionBufferSize / sizeof(float)];
-
- region[0] = srcRegion.X1 / (float)src.Width;
- region[1] = srcRegion.X2 / (float)src.Width;
- region[2] = srcRegion.Y1 / (float)src.Height;
- region[3] = srcRegion.Y2 / (float)src.Height;
-
- if (dstRegion.X1 > dstRegion.X2)
- {
- (region[0], region[1]) = (region[1], region[0]);
- }
-
- if (dstRegion.Y1 > dstRegion.Y2)
- {
- (region[2], region[3]) = (region[3], region[2]);
- }
-
- using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, RegionBufferSize);
- buffer.Holder.SetDataUnchecked(buffer.Offset, region);
- _pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
-
- Span viewports = stackalloc Viewport[16];
-
- Rectangle rect = new(
- MathF.Min(dstRegion.X1, dstRegion.X2),
- MathF.Min(dstRegion.Y1, dstRegion.Y2),
- MathF.Abs(dstRegion.X2 - dstRegion.X1),
- MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
-
- viewports[0] = new Viewport(
- rect,
- ViewportSwizzle.PositiveX,
- ViewportSwizzle.PositiveY,
- ViewportSwizzle.PositiveZ,
- ViewportSwizzle.PositiveW,
- 0f,
- 1f);
-
- int dstWidth = dst.Width;
- int dstHeight = dst.Height;
-
- Span> scissors = stackalloc Rectangle[16];
-
- scissors[0] = new Rectangle(0, 0, dstWidth, dstHeight);
-
- _pipeline.SetRenderTargets([], dst);
- _pipeline.SetScissors(scissors);
- _pipeline.SetViewports(viewports);
- _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
-
- if (src.Info.Format is
- Format.D16Unorm or
- Format.D32Float or
- Format.X8UintD24Unorm or
- Format.D24UnormS8Uint or
- Format.D32FloatS8Uint or
- Format.S8UintD24Unorm)
- {
- Texture depthTexture = CreateDepthOrStencilView(src, DepthStencilMode.Depth);
-
- BlitDepthStencilDraw(depthTexture, isDepth: true);
-
- if (depthTexture != src)
- {
- depthTexture.Release();
- }
- }
-
- if (src.Info.Format is
- Format.S8Uint or
- Format.D24UnormS8Uint or
- Format.D32FloatS8Uint or
- Format.S8UintD24Unorm)
- {
- Texture stencilTexture = CreateDepthOrStencilView(src, DepthStencilMode.Stencil);
-
- BlitDepthStencilDraw(stencilTexture, isDepth: false);
-
- if (stencilTexture != src)
- {
- stencilTexture.Release();
- }
- }
-
- // Restore previous state
- _pipeline.SwapState(null);
- }
-
- private static Texture CreateDepthOrStencilView(Texture depthStencilTexture, DepthStencilMode depthStencilMode)
- {
- if (depthStencilTexture.Info.DepthStencilMode == depthStencilMode)
- {
- return depthStencilTexture;
- }
-
- return (Texture)depthStencilTexture.CreateView(new TextureCreateInfo(
- depthStencilTexture.Info.Width,
- depthStencilTexture.Info.Height,
- depthStencilTexture.Info.Depth,
- depthStencilTexture.Info.Levels,
- depthStencilTexture.Info.Samples,
- depthStencilTexture.Info.BlockWidth,
- depthStencilTexture.Info.BlockHeight,
- depthStencilTexture.Info.BytesPerPixel,
- depthStencilTexture.Info.Format,
- depthStencilMode,
- depthStencilTexture.Info.Target,
- SwizzleComponent.Red,
- SwizzleComponent.Green,
- SwizzleComponent.Blue,
- SwizzleComponent.Alpha), 0, 0);
- }
-
- private void BlitDepthStencilDraw(Texture src, bool isDepth)
- {
- // TODO: Check this https://github.com/Ryujinx/Ryujinx/pull/5003/
- _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, _samplerNearest);
-
- string debugGroupName;
-
- if (isDepth)
- {
- debugGroupName = "Depth Blit";
- _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
- _pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
- }
- else
- {
- debugGroupName = "Stencil Blit";
- _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit);
- _pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
- }
-
- _pipeline.Draw(4, 1, 0, 0, debugGroupName);
-
- if (isDepth)
- {
- _pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
- }
- else
- {
- _pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
- }
- }
-
- public unsafe void DrawTexture(
- ITexture src,
- ISampler srcSampler,
- Extents2DF srcRegion,
- Extents2DF dstRegion)
- {
- // Save current state
- PredrawState state = _pipeline.SavePredrawState();
-
- _pipeline.SetFaceCulling(false, Face.Front);
- _pipeline.SetStencilTest(new StencilTestDescriptor());
- _pipeline.SetDepthTest(new DepthTestDescriptor());
-
- const int RegionBufferSize = 16;
-
- _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
-
- Span region = stackalloc float[RegionBufferSize / sizeof(float)];
-
- region[0] = srcRegion.X1 / src.Width;
- region[1] = srcRegion.X2 / src.Width;
- region[2] = srcRegion.Y1 / src.Height;
- region[3] = srcRegion.Y2 / src.Height;
-
- if (dstRegion.X1 > dstRegion.X2)
- {
- (region[0], region[1]) = (region[1], region[0]);
- }
-
- if (dstRegion.Y1 > dstRegion.Y2)
- {
- (region[2], region[3]) = (region[3], region[2]);
- }
-
- BufferHandle bufferHandle = _renderer.BufferManager.CreateWithHandle(RegionBufferSize);
- _renderer.BufferManager.SetData(bufferHandle, 0, region);
- _pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(bufferHandle, 0, RegionBufferSize))]);
-
- Span viewports = stackalloc Viewport[16];
-
- Rectangle rect = new(
- MathF.Min(dstRegion.X1, dstRegion.X2),
- MathF.Min(dstRegion.Y1, dstRegion.Y2),
- MathF.Abs(dstRegion.X2 - dstRegion.X1),
- MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
-
- viewports[0] = new Viewport(
- rect,
- ViewportSwizzle.PositiveX,
- ViewportSwizzle.PositiveY,
- ViewportSwizzle.PositiveZ,
- ViewportSwizzle.PositiveW,
- 0f,
- 1f);
-
- _pipeline.SetProgram(_programColorBlitF);
- _pipeline.SetViewports(viewports);
- _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
- _pipeline.Draw(4, 1, 0, 0, "Draw Texture");
-
- _renderer.BufferManager.Delete(bufferHandle);
-
- // Restore previous state
- _pipeline.RestorePredrawState(state);
- }
-
- public void ConvertI8ToI16(CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
- {
- ChangeStride(cbs, src, dst, srcOffset, size, 1, 2);
- }
-
- public unsafe void ChangeStride(
- CommandBufferScoped cbs,
- BufferHolder src,
- BufferHolder dst,
- int srcOffset,
- int size,
- int stride,
- int newStride)
- {
- int elems = size / stride;
-
- Auto srcBuffer = src.GetBuffer();
- Auto dstBuffer = dst.GetBuffer();
-
- const int ParamsBufferSize = 4 * sizeof(int);
-
- // Save current state
- _pipeline.SwapState(_helperShaderState);
-
- Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
-
- shaderParams[0] = stride;
- shaderParams[1] = newStride;
- shaderParams[2] = size;
- shaderParams[3] = srcOffset;
-
- using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
- buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams);
- _pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
-
- Span> sbRanges = new Auto[2];
-
- sbRanges[0] = srcBuffer;
- sbRanges[1] = dstBuffer;
- _pipeline.SetStorageBuffers(1, sbRanges);
-
- _pipeline.SetProgram(_programStrideChange);
- _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1, "Change Stride");
-
- // Restore previous state
- _pipeline.SwapState(null);
- }
-
- public unsafe void ConvertD32S8ToD24S8(CommandBufferScoped cbs, BufferHolder src, Auto dstBuffer, int pixelCount, int dstOffset)
- {
- int inSize = pixelCount * 2 * sizeof(int);
-
- Auto srcBuffer = src.GetBuffer();
-
- const int ParamsBufferSize = sizeof(int) * 2;
-
- // Save current state
- _pipeline.SwapState(_helperShaderState);
-
- Span shaderParams = stackalloc int[2];
-
- shaderParams[0] = pixelCount;
- shaderParams[1] = dstOffset;
-
- using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
- buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams);
- _pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
-
- Span> sbRanges = new Auto[2];
-
- sbRanges[0] = srcBuffer;
- sbRanges[1] = dstBuffer;
- _pipeline.SetStorageBuffers(1, sbRanges);
-
- _pipeline.SetProgram(_programConvertD32S8ToD24S8);
- _pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1, "D32S8 to D24S8 Conversion");
-
- // Restore previous state
- _pipeline.SwapState(null);
- }
-
- public void ConvertIndexBuffer(
- CommandBufferScoped cbs,
- BufferHolder src,
- BufferHolder dst,
- IndexBufferPattern pattern,
- int indexSize,
- int srcOffset,
- int indexCount)
- {
- // TODO: Support conversion with primitive restart enabled.
-
- int primitiveCount = pattern.GetPrimitiveCount(indexCount);
- int outputIndexSize = 4;
-
- Auto srcBuffer = src.GetBuffer();
- Auto dstBuffer = dst.GetBuffer();
-
- const int ParamsBufferSize = 16 * sizeof(int);
-
- // Save current state
- _pipeline.SwapState(_helperShaderState);
-
- Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
-
- shaderParams[8] = pattern.PrimitiveVertices;
- shaderParams[9] = pattern.PrimitiveVerticesOut;
- shaderParams[10] = indexSize;
- shaderParams[11] = outputIndexSize;
- shaderParams[12] = pattern.BaseIndex;
- shaderParams[13] = pattern.IndexStride;
- shaderParams[14] = srcOffset;
- shaderParams[15] = primitiveCount;
-
- pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
-
- using ScopedTemporaryBuffer patternScoped = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
- patternScoped.Holder.SetDataUnchecked(patternScoped.Offset, shaderParams);
-
- Span> sbRanges = new Auto[2];
-
- sbRanges[0] = srcBuffer;
- sbRanges[1] = dstBuffer;
- _pipeline.SetStorageBuffers(1, sbRanges);
- _pipeline.SetStorageBuffers([new BufferAssignment(3, patternScoped.Range)]);
-
- _pipeline.SetProgram(_programConvertIndexBuffer);
- _pipeline.DispatchCompute(BitUtils.DivRoundUp(primitiveCount, 16), 1, 1, "Convert Index Buffer");
-
- // Restore previous state
- _pipeline.SwapState(null);
- }
-
- public unsafe void ClearColor(
- int index,
- ReadOnlySpan clearColor,
- uint componentMask,
- int dstWidth,
- int dstHeight,
- Format format)
- {
- // Keep original scissor
- DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
-
- // Save current state
- EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags, false);
-
- // Inherit some state without fully recreating render pipeline.
- RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, false, index);
-
- const int ClearColorBufferSize = 16;
-
- // TODO: Flush
-
- using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearColorBufferSize);
- buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor);
- _pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
-
- Span viewports = stackalloc Viewport[16];
-
- // TODO: Set exact viewport!
- viewports[0] = new Viewport(
- new Rectangle(0, 0, dstWidth, dstHeight),
- ViewportSwizzle.PositiveX,
- ViewportSwizzle.PositiveY,
- ViewportSwizzle.PositiveZ,
- ViewportSwizzle.PositiveW,
- 0f,
- 1f);
-
- Span componentMasks = stackalloc uint[index + 1];
- componentMasks[index] = componentMask;
-
- string debugGroupName = "Clear Color ";
-
- if (format.IsSint())
- {
- debugGroupName += "Int";
- _pipeline.SetProgram(_programsColorClearI[index]);
- }
- else if (format.IsUint())
- {
- debugGroupName += "UInt";
- _pipeline.SetProgram(_programsColorClearU[index]);
- }
- else
- {
- debugGroupName += "Float";
- _pipeline.SetProgram(_programsColorClearF[index]);
- }
-
- _pipeline.SetBlendState(index, new BlendDescriptor());
- _pipeline.SetFaceCulling(false, Face.Front);
- _pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
- _pipeline.SetRenderTargetColorMasks(componentMasks);
- _pipeline.SetViewports(viewports);
- _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
- _pipeline.Draw(4, 1, 0, 0, debugGroupName);
-
- // Restore previous state
- _pipeline.SwapState(null, clearFlags, false);
-
- _helperShaderState.Restore(save);
- }
-
- public unsafe void ClearDepthStencil(
- float depthValue,
- bool depthMask,
- int stencilValue,
- int stencilMask,
- int dstWidth,
- int dstHeight)
- {
- // Keep original scissor
- DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
- MTLScissorRect[] helperScissors = _helperShaderState.Scissors;
-
- // Save current state
- EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags, false);
-
- // Inherit some state without fully recreating render pipeline.
- RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, true);
-
- const int ClearDepthBufferSize = 16;
-
- using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearDepthBufferSize);
- buffer.Holder.SetDataUnchecked(buffer.Offset, new ReadOnlySpan(ref depthValue));
- _pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
-
- Span viewports = stackalloc Viewport[1];
-
- viewports[0] = new Viewport(
- new Rectangle(0, 0, dstWidth, dstHeight),
- ViewportSwizzle.PositiveX,
- ViewportSwizzle.PositiveY,
- ViewportSwizzle.PositiveZ,
- ViewportSwizzle.PositiveW,
- 0f,
- 1f);
-
- _pipeline.SetProgram(_programDepthStencilClear);
- _pipeline.SetFaceCulling(false, Face.Front);
- _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
- _pipeline.SetViewports(viewports);
- _pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
- _pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
- _pipeline.Draw(4, 1, 0, 0, "Clear Depth Stencil");
-
- // Cleanup
- _pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
- _pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
-
- // Restore previous state
- _pipeline.SwapState(null, clearFlags, false);
-
- _helperShaderState.Restore(save);
- }
-
- private static StencilTestDescriptor CreateStencilTestDescriptor(
- bool enabled,
- int refValue = 0,
- int compareMask = 0xff,
- int writeMask = 0xff)
- {
- return new StencilTestDescriptor(
- enabled,
- CompareOp.Always,
- StencilOp.Replace,
- StencilOp.Replace,
- StencilOp.Replace,
- refValue,
- compareMask,
- writeMask,
- CompareOp.Always,
- StencilOp.Replace,
- StencilOp.Replace,
- StencilOp.Replace,
- refValue,
- compareMask,
- writeMask);
- }
-
- public void Dispose()
- {
- _programColorBlitF.Dispose();
- _programColorBlitI.Dispose();
- _programColorBlitU.Dispose();
- _programColorBlitMsF.Dispose();
- _programColorBlitMsI.Dispose();
- _programColorBlitMsU.Dispose();
-
- foreach (IProgram programColorClear in _programsColorClearF)
- {
- programColorClear.Dispose();
- }
-
- foreach (IProgram programColorClear in _programsColorClearU)
- {
- programColorClear.Dispose();
- }
-
- foreach (IProgram programColorClear in _programsColorClearI)
- {
- programColorClear.Dispose();
- }
-
- _programDepthStencilClear.Dispose();
- _pipeline.Dispose();
- _samplerLinear.Dispose();
- _samplerNearest.Dispose();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/IdList.cs b/src/Ryujinx.Graphics.Metal/IdList.cs
deleted file mode 100644
index 72c9d5fcc..000000000
--- a/src/Ryujinx.Graphics.Metal/IdList.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Metal
-{
- class IdList where T : class
- {
- private readonly List _list;
- private int _freeMin;
-
- public IdList()
- {
- _list = [];
- _freeMin = 0;
- }
-
- public int Add(T value)
- {
- int id;
- int count = _list.Count;
- id = _list.IndexOf(null, _freeMin);
-
- if ((uint)id < (uint)count)
- {
- _list[id] = value;
- }
- else
- {
- id = count;
- _freeMin = id + 1;
-
- _list.Add(value);
- }
-
- return id + 1;
- }
-
- public void Remove(int id)
- {
- id--;
-
- int count = _list.Count;
-
- if ((uint)id >= (uint)count)
- {
- return;
- }
-
- if (id + 1 == count)
- {
- // Trim unused items.
- int removeIndex = id;
-
- while (removeIndex > 0 && _list[removeIndex - 1] == null)
- {
- removeIndex--;
- }
-
- _list.RemoveRange(removeIndex, count - removeIndex);
-
- if (_freeMin > removeIndex)
- {
- _freeMin = removeIndex;
- }
- }
- else
- {
- _list[id] = null;
-
- if (_freeMin > id)
- {
- _freeMin = id;
- }
- }
- }
-
- public bool TryGetValue(int id, out T value)
- {
- id--;
-
- try
- {
- if ((uint)id < (uint)_list.Count)
- {
- value = _list[id];
- return value != null;
- }
-
- value = null;
- return false;
- }
- catch (ArgumentOutOfRangeException)
- {
- value = null;
- return false;
- }
- catch (IndexOutOfRangeException)
- {
- value = null;
- return false;
- }
- }
-
- public void Clear()
- {
- _list.Clear();
- _freeMin = 0;
- }
-
- public IEnumerator GetEnumerator()
- {
- for (int i = 0; i < _list.Count; i++)
- {
- if (_list[i] != null)
- {
- yield return _list[i];
- }
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/ImageArray.cs b/src/Ryujinx.Graphics.Metal/ImageArray.cs
deleted file mode 100644
index 9fa0df09d..000000000
--- a/src/Ryujinx.Graphics.Metal/ImageArray.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- internal class ImageArray : IImageArray
- {
- private readonly TextureRef[] _textureRefs;
- private readonly TextureBuffer[] _bufferTextureRefs;
-
- private readonly bool _isBuffer;
- private readonly Pipeline _pipeline;
-
- public ImageArray(int size, bool isBuffer, Pipeline pipeline)
- {
- if (isBuffer)
- {
- _bufferTextureRefs = new TextureBuffer[size];
- }
- else
- {
- _textureRefs = new TextureRef[size];
- }
-
- _isBuffer = isBuffer;
- _pipeline = pipeline;
- }
-
- public void SetImages(int index, ITexture[] images)
- {
- for (int i = 0; i < images.Length; i++)
- {
- ITexture image = images[i];
-
- if (image is TextureBuffer textureBuffer)
- {
- _bufferTextureRefs[index + i] = textureBuffer;
- }
- else if (image is Texture texture)
- {
- _textureRefs[index + i].Storage = texture;
- }
- else if (!_isBuffer)
- {
- _textureRefs[index + i].Storage = null;
- }
- else
- {
- _bufferTextureRefs[index + i] = null;
- }
- }
-
- SetDirty();
- }
-
- public TextureRef[] GetTextureRefs()
- {
- return _textureRefs;
- }
-
- public TextureBuffer[] GetBufferTextureRefs()
- {
- return _bufferTextureRefs;
- }
-
- private void SetDirty()
- {
- _pipeline.DirtyImages();
- }
-
- public void Dispose() { }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/IndexBufferPattern.cs b/src/Ryujinx.Graphics.Metal/IndexBufferPattern.cs
deleted file mode 100644
index 24e3222fe..000000000
--- a/src/Ryujinx.Graphics.Metal/IndexBufferPattern.cs
+++ /dev/null
@@ -1,118 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using System;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- internal class IndexBufferPattern : IDisposable
- {
- public int PrimitiveVertices { get; }
- public int PrimitiveVerticesOut { get; }
- public int BaseIndex { get; }
- public int[] OffsetIndex { get; }
- public int IndexStride { get; }
- public bool RepeatStart { get; }
-
- private readonly MetalRenderer _renderer;
- private int _currentSize;
- private BufferHandle _repeatingBuffer;
-
- public IndexBufferPattern(MetalRenderer renderer,
- int primitiveVertices,
- int primitiveVerticesOut,
- int baseIndex,
- int[] offsetIndex,
- int indexStride,
- bool repeatStart)
- {
- PrimitiveVertices = primitiveVertices;
- PrimitiveVerticesOut = primitiveVerticesOut;
- BaseIndex = baseIndex;
- OffsetIndex = offsetIndex;
- IndexStride = indexStride;
- RepeatStart = repeatStart;
-
- _renderer = renderer;
- }
-
- public int GetPrimitiveCount(int vertexCount)
- {
- return Math.Max(0, (vertexCount - BaseIndex) / IndexStride);
- }
-
- public int GetConvertedCount(int indexCount)
- {
- int primitiveCount = GetPrimitiveCount(indexCount);
- return primitiveCount * OffsetIndex.Length;
- }
-
- public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount)
- {
- int primitiveCount = GetPrimitiveCount(vertexCount);
- indexCount = primitiveCount * PrimitiveVerticesOut;
-
- int expectedSize = primitiveCount * OffsetIndex.Length;
-
- if (expectedSize <= _currentSize && _repeatingBuffer != BufferHandle.Null)
- {
- return _repeatingBuffer;
- }
-
- // Expand the repeating pattern to the number of requested primitives.
- BufferHandle newBuffer = _renderer.BufferManager.CreateWithHandle(expectedSize * sizeof(int));
-
- // Copy the old data to the new one.
- if (_repeatingBuffer != BufferHandle.Null)
- {
- _renderer.Pipeline.CopyBuffer(_repeatingBuffer, newBuffer, 0, 0, _currentSize * sizeof(int));
- _renderer.BufferManager.Delete(_repeatingBuffer);
- }
-
- _repeatingBuffer = newBuffer;
-
- // Add the additional repeats on top.
- int newPrimitives = primitiveCount;
- int oldPrimitives = (_currentSize) / OffsetIndex.Length;
-
- int[] newData;
-
- newPrimitives -= oldPrimitives;
- newData = new int[expectedSize - _currentSize];
-
- int outOffset = 0;
- int index = oldPrimitives * IndexStride + BaseIndex;
-
- for (int i = 0; i < newPrimitives; i++)
- {
- if (RepeatStart)
- {
- // Used for triangle fan
- newData[outOffset++] = 0;
- }
-
- for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++)
- {
- newData[outOffset++] = index + OffsetIndex[j];
- }
-
- index += IndexStride;
- }
-
- _renderer.SetBufferData(newBuffer, _currentSize * sizeof(int), MemoryMarshal.Cast(newData));
- _currentSize = expectedSize;
-
- return newBuffer;
- }
-
- public void Dispose()
- {
- if (_repeatingBuffer != BufferHandle.Null)
- {
- _renderer.BufferManager.Delete(_repeatingBuffer);
- _repeatingBuffer = BufferHandle.Null;
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/IndexBufferState.cs b/src/Ryujinx.Graphics.Metal/IndexBufferState.cs
deleted file mode 100644
index 02c9ff9ef..000000000
--- a/src/Ryujinx.Graphics.Metal/IndexBufferState.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- readonly internal struct IndexBufferState
- {
- public static IndexBufferState Null => new(BufferHandle.Null, 0, 0);
-
- private readonly int _offset;
- private readonly int _size;
- private readonly IndexType _type;
-
- private readonly BufferHandle _handle;
-
- public IndexBufferState(BufferHandle handle, int offset, int size, IndexType type = IndexType.UInt)
- {
- _handle = handle;
- _offset = offset;
- _size = size;
- _type = type;
- }
-
- public (MTLBuffer, int, MTLIndexType) GetIndexBuffer(MetalRenderer renderer, CommandBufferScoped cbs)
- {
- Auto autoBuffer;
- int offset, size;
- MTLIndexType type;
-
- if (_type == IndexType.UByte)
- {
- // Index type is not supported. Convert to I16.
- autoBuffer = renderer.BufferManager.GetBufferI8ToI16(cbs, _handle, _offset, _size);
-
- type = MTLIndexType.UInt16;
- offset = 0;
- size = _size * 2;
- }
- else
- {
- autoBuffer = renderer.BufferManager.GetBuffer(_handle, false, out int bufferSize);
-
- if (_offset >= bufferSize)
- {
- autoBuffer = null;
- }
-
- type = _type.Convert();
- offset = _offset;
- size = _size;
- }
-
- if (autoBuffer != null)
- {
- DisposableBuffer buffer = autoBuffer.Get(cbs, offset, size);
-
- return (buffer.Value, offset, type);
- }
-
- return (new MTLBuffer(IntPtr.Zero), 0, MTLIndexType.UInt16);
- }
-
- public (MTLBuffer, int, MTLIndexType) GetConvertedIndexBuffer(
- MetalRenderer renderer,
- CommandBufferScoped cbs,
- int firstIndex,
- int indexCount,
- int convertedCount,
- IndexBufferPattern pattern)
- {
- // Convert the index buffer using the given pattern.
- int indexSize = GetIndexSize();
-
- int firstIndexOffset = firstIndex * indexSize;
-
- Auto autoBuffer = renderer.BufferManager.GetBufferTopologyConversion(cbs, _handle, _offset + firstIndexOffset, indexCount * indexSize, pattern, indexSize);
-
- int size = convertedCount * 4;
-
- if (autoBuffer != null)
- {
- DisposableBuffer buffer = autoBuffer.Get(cbs, 0, size);
-
- return (buffer.Value, 0, MTLIndexType.UInt32);
- }
-
- return (new MTLBuffer(IntPtr.Zero), 0, MTLIndexType.UInt32);
- }
-
- private int GetIndexSize()
- {
- return _type switch
- {
- IndexType.UInt => 4,
- IndexType.UShort => 2,
- _ => 1,
- };
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs
deleted file mode 100644
index 86e2451b3..000000000
--- a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs
+++ /dev/null
@@ -1,312 +0,0 @@
-using Ryujinx.Common.Configuration;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader.Translation;
-using SharpMetal.Metal;
-using SharpMetal.QuartzCore;
-using System;
-using System.Collections.Generic;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- public sealed class MetalRenderer : IRenderer
- {
- public const int TotalSets = 4;
-
- private readonly MTLDevice _device;
- private readonly MTLCommandQueue _queue;
- private readonly Func _getMetalLayer;
-
- private Pipeline _pipeline;
- private Window _window;
-
- public uint ProgramCount { get; set; }
-
-#pragma warning disable CS0067 // The event is never used
- public event EventHandler ScreenCaptured;
-#pragma warning restore CS0067
-
- public bool PreferThreading => true;
- public IPipeline Pipeline => _pipeline;
- public IWindow Window => _window;
-
- internal MTLCommandQueue BackgroundQueue { get; private set; }
- internal HelperShader HelperShader { get; private set; }
- internal BufferManager BufferManager { get; private set; }
- internal CommandBufferPool CommandBufferPool { get; private set; }
- internal BackgroundResources BackgroundResources { get; private set; }
- internal Action InterruptAction { get; private set; }
- internal SyncManager SyncManager { get; private set; }
-
- internal HashSet Programs { get; }
- internal HashSet Samplers { get; }
-
- public MetalRenderer(Func metalLayer)
- {
- _device = MTLDevice.CreateSystemDefaultDevice();
- Programs = [];
- Samplers = [];
-
- if (_device.ArgumentBuffersSupport != MTLArgumentBuffersTier.Tier2)
- {
- throw new NotSupportedException("Metal backend requires Tier 2 Argument Buffer support.");
- }
-
- _queue = _device.NewCommandQueue(CommandBufferPool.MaxCommandBuffers + 1);
- BackgroundQueue = _device.NewCommandQueue(CommandBufferPool.MaxCommandBuffers);
-
- _getMetalLayer = metalLayer;
- }
-
- public void Initialize(GraphicsDebugLevel logLevel)
- {
- CAMetalLayer layer = _getMetalLayer();
- layer.Device = _device;
- layer.FramebufferOnly = false;
-
- CommandBufferPool = new CommandBufferPool(_queue);
- _window = new Window(this, layer);
- _pipeline = new Pipeline(_device, this);
- BufferManager = new BufferManager(_device, this, _pipeline);
-
- _pipeline.InitEncoderStateManager(BufferManager);
-
- BackgroundResources = new BackgroundResources(this);
- HelperShader = new HelperShader(_device, this, _pipeline);
- SyncManager = new SyncManager(this);
- }
-
- public void BackgroundContextAction(Action action, bool alwaysBackground = false)
- {
- // GetData methods should be thread safe, so we can call this directly.
- // Texture copy (scaled) may also happen in here, so that should also be thread safe.
-
- action();
- }
-
- public BufferHandle CreateBuffer(int size, BufferAccess access)
- {
- return BufferManager.CreateWithHandle(size);
- }
-
- public BufferHandle CreateBuffer(IntPtr pointer, int size)
- {
- return BufferManager.Create(pointer, size);
- }
-
- public BufferHandle CreateBufferSparse(ReadOnlySpan storageBuffers)
- {
- throw new NotImplementedException();
- }
-
- public IImageArray CreateImageArray(int size, bool isBuffer)
- {
- return new ImageArray(size, isBuffer, _pipeline);
- }
-
- public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
- {
- ProgramCount++;
- return new Program(this, _device, shaders, info.ResourceLayout, info.ComputeLocalSize);
- }
-
- public ISampler CreateSampler(SamplerCreateInfo info)
- {
- return new SamplerHolder(this, _device, info);
- }
-
- public ITexture CreateTexture(TextureCreateInfo info)
- {
- if (info.Target == Target.TextureBuffer)
- {
- return new TextureBuffer(_device, this, _pipeline, info);
- }
-
- return new Texture(_device, this, _pipeline, info);
- }
-
- public ITextureArray CreateTextureArray(int size, bool isBuffer)
- {
- return new TextureArray(size, isBuffer, _pipeline);
- }
-
- public bool PrepareHostMapping(IntPtr address, ulong size)
- {
- // TODO: Metal Host Mapping
- return false;
- }
-
- public void CreateSync(ulong id, bool strict)
- {
- SyncManager.Create(id, strict);
- }
-
- public void DeleteBuffer(BufferHandle buffer)
- {
- BufferManager.Delete(buffer);
- }
-
- public PinnedSpan GetBufferData(BufferHandle buffer, int offset, int size)
- {
- return BufferManager.GetData(buffer, offset, size);
- }
-
- public Capabilities GetCapabilities()
- {
- // TODO: Finalize these values
- return new Capabilities(
- api: TargetApi.Metal,
- vendorName: HardwareInfoTools.GetVendor(),
- SystemMemoryType.UnifiedMemory,
- hasFrontFacingBug: false,
- hasVectorIndexingBug: false,
- needsFragmentOutputSpecialization: true,
- reduceShaderPrecision: true,
- supportsAstcCompression: true,
- supportsBc123Compression: true,
- supportsBc45Compression: true,
- supportsBc67Compression: true,
- supportsEtc2Compression: true,
- supports3DTextureCompression: true,
- supportsBgraFormat: true,
- supportsR4G4Format: false,
- supportsR4G4B4A4Format: true,
- supportsScaledVertexFormats: false,
- supportsSnormBufferTextureFormat: true,
- supportsSparseBuffer: false,
- supports5BitComponentFormat: true,
- supportsBlendEquationAdvanced: false,
- supportsFragmentShaderInterlock: true,
- supportsFragmentShaderOrderingIntel: false,
- supportsGeometryShader: false,
- supportsGeometryShaderPassthrough: false,
- supportsTransformFeedback: false,
- supportsImageLoadFormatted: false,
- supportsLayerVertexTessellation: false,
- supportsMismatchingViewFormat: true,
- supportsCubemapView: true,
- supportsNonConstantTextureOffset: false,
- supportsQuads: false,
- supportsSeparateSampler: true,
- supportsShaderBallot: false,
- supportsShaderBarrierDivergence: false,
- supportsShaderFloat64: false,
- supportsTextureGatherOffsets: false,
- supportsTextureShadowLod: false,
- supportsVertexStoreAndAtomics: false,
- supportsViewportIndexVertexTessellation: false,
- supportsViewportMask: false,
- supportsViewportSwizzle: false,
- supportsIndirectParameters: true,
- supportsDepthClipControl: false,
- uniformBufferSetIndex: (int)Constants.ConstantBuffersSetIndex,
- storageBufferSetIndex: (int)Constants.StorageBuffersSetIndex,
- textureSetIndex: (int)Constants.TexturesSetIndex,
- imageSetIndex: (int)Constants.ImagesSetIndex,
- extraSetBaseIndex: TotalSets,
- maximumExtraSets: (int)Constants.MaximumExtraSets,
- maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
- maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
- maximumTexturesPerStage: Constants.MaxTexturesPerStage,
- maximumImagesPerStage: Constants.MaxImagesPerStage,
- maximumComputeSharedMemorySize: (int)_device.MaxThreadgroupMemoryLength,
- maximumSupportedAnisotropy: 16,
- shaderSubgroupSize: 256,
- storageBufferOffsetAlignment: 16,
- textureBufferOffsetAlignment: 16,
- gatherBiasPrecision: 0,
- maximumGpuMemory: 0
- );
- }
-
- public ulong GetCurrentSync()
- {
- return SyncManager.GetCurrent();
- }
-
- public HardwareInfo GetHardwareInfo()
- {
- return new HardwareInfo(HardwareInfoTools.GetVendor(), HardwareInfoTools.GetModel(), "Apple");
- }
-
- public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
- {
- throw new NotImplementedException();
- }
-
- public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data)
- {
- BufferManager.SetData(buffer, offset, data, _pipeline.Cbs);
- }
-
- public void UpdateCounters()
- {
- // https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
- }
-
- public void PreFrame()
- {
- SyncManager.Cleanup();
- }
-
- public ICounterEvent ReportCounter(CounterType type, EventHandler resultHandler, float divisor, bool hostReserved)
- {
- // https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
- CounterEvent counterEvent = new();
- resultHandler?.Invoke(counterEvent, type == CounterType.SamplesPassed ? (ulong)1 : 0);
- return counterEvent;
- }
-
- public void ResetCounter(CounterType type)
- {
- // https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
- }
-
- public void WaitSync(ulong id)
- {
- SyncManager.Wait(id);
- }
-
- public void FlushAllCommands()
- {
- _pipeline.FlushCommandsImpl();
- }
-
- public void RegisterFlush()
- {
- SyncManager.RegisterFlush();
-
- // Periodically free unused regions of the staging buffer to avoid doing it all at once.
- BufferManager.StagingBuffer.FreeCompleted();
- }
-
- public void SetInterruptAction(Action interruptAction)
- {
- InterruptAction = interruptAction;
- }
-
- public void Screenshot()
- {
- // TODO: Screenshots
- }
-
- public void Dispose()
- {
- BackgroundResources.Dispose();
-
- foreach (Program program in Programs)
- {
- program.Dispose();
- }
-
- foreach (SamplerHolder sampler in Samplers)
- {
- sampler.Dispose();
- }
-
- _pipeline.Dispose();
- _window.Dispose();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/MultiFenceHolder.cs b/src/Ryujinx.Graphics.Metal/MultiFenceHolder.cs
deleted file mode 100644
index 89ae1fa77..000000000
--- a/src/Ryujinx.Graphics.Metal/MultiFenceHolder.cs
+++ /dev/null
@@ -1,262 +0,0 @@
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- ///
- /// Holder for multiple host GPU fences.
- ///
- [SupportedOSPlatform("macos")]
- class MultiFenceHolder
- {
- private const int BufferUsageTrackingGranularity = 4096;
-
- private readonly FenceHolder[] _fences;
- private readonly BufferUsageBitmap _bufferUsageBitmap;
-
- ///
- /// Creates a new instance of the multiple fence holder.
- ///
- public MultiFenceHolder()
- {
- _fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
- }
-
- ///
- /// Creates a new instance of the multiple fence holder, with a given buffer size in mind.
- ///
- /// Size of the buffer
- public MultiFenceHolder(int size)
- {
- _fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
- _bufferUsageBitmap = new BufferUsageBitmap(size, BufferUsageTrackingGranularity);
- }
-
- ///
- /// Adds read/write buffer usage information to the uses list.
- ///
- /// Index of the command buffer where the buffer is used
- /// Offset of the buffer being used
- /// Size of the buffer region being used, in bytes
- /// Whether the access is a write or not
- public void AddBufferUse(int cbIndex, int offset, int size, bool write)
- {
- _bufferUsageBitmap.Add(cbIndex, offset, size, false);
-
- if (write)
- {
- _bufferUsageBitmap.Add(cbIndex, offset, size, true);
- }
- }
-
- ///
- /// Removes all buffer usage information for a given command buffer.
- ///
- /// Index of the command buffer where the buffer is used
- public void RemoveBufferUses(int cbIndex)
- {
- _bufferUsageBitmap?.Clear(cbIndex);
- }
-
- ///
- /// Checks if a given range of a buffer is being used by a command buffer still being processed by the GPU.
- ///
- /// Index of the command buffer where the buffer is used
- /// Offset of the buffer being used
- /// Size of the buffer region being used, in bytes
- /// True if in use, false otherwise
- public bool IsBufferRangeInUse(int cbIndex, int offset, int size)
- {
- return _bufferUsageBitmap.OverlapsWith(cbIndex, offset, size);
- }
-
- ///
- /// Checks if a given range of a buffer is being used by any command buffer still being processed by the GPU.
- ///
- /// Offset of the buffer being used
- /// Size of the buffer region being used, in bytes
- /// True if only write usages should count
- /// True if in use, false otherwise
- public bool IsBufferRangeInUse(int offset, int size, bool write)
- {
- return _bufferUsageBitmap.OverlapsWith(offset, size, write);
- }
-
- ///
- /// Adds a fence to the holder.
- ///
- /// Command buffer index of the command buffer that owns the fence
- /// Fence to be added
- /// True if the command buffer's previous fence value was null
- public bool AddFence(int cbIndex, FenceHolder fence)
- {
- ref FenceHolder fenceRef = ref _fences[cbIndex];
-
- if (fenceRef == null)
- {
- fenceRef = fence;
- return true;
- }
-
- return false;
- }
-
- ///
- /// Removes a fence from the holder.
- ///
- /// Command buffer index of the command buffer that owns the fence
- public void RemoveFence(int cbIndex)
- {
- _fences[cbIndex] = null;
- }
-
- ///
- /// Determines if a fence referenced on the given command buffer.
- ///
- /// Index of the command buffer to check if it's used
- /// True if referenced, false otherwise
- public bool HasFence(int cbIndex)
- {
- return _fences[cbIndex] != null;
- }
-
- ///
- /// Wait until all the fences on the holder are signaled.
- ///
- public void WaitForFences()
- {
- WaitForFencesImpl(0, 0, true);
- }
-
- ///
- /// Wait until all the fences on the holder with buffer uses overlapping the specified range are signaled.
- ///
- /// Start offset of the buffer range
- /// Size of the buffer range in bytes
- public void WaitForFences(int offset, int size)
- {
- WaitForFencesImpl(offset, size, true);
- }
-
- ///
- /// Wait until all the fences on the holder with buffer uses overlapping the specified range are signaled.
- ///
-
- // TODO: Add a proper timeout!
- public bool WaitForFences(bool indefinite)
- {
- return WaitForFencesImpl(0, 0, indefinite);
- }
-
- ///
- /// Wait until all the fences on the holder with buffer uses overlapping the specified range are signaled.
- ///
- /// Start offset of the buffer range
- /// Size of the buffer range in bytes
- /// Indicates if this should wait indefinitely
- /// True if all fences were signaled before the timeout expired, false otherwise
- private bool WaitForFencesImpl(int offset, int size, bool indefinite)
- {
- Span fenceHolders = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
-
- int count = size != 0 ? GetOverlappingFences(fenceHolders, offset, size) : GetFences(fenceHolders);
- Span fences = stackalloc MTLCommandBuffer[count];
-
- int fenceCount = 0;
-
- for (int i = 0; i < count; i++)
- {
- if (fenceHolders[i].TryGet(out MTLCommandBuffer fence))
- {
- fences[fenceCount] = fence;
-
- if (fenceCount < i)
- {
- fenceHolders[fenceCount] = fenceHolders[i];
- }
-
- fenceCount++;
- }
- }
-
- if (fenceCount == 0)
- {
- return true;
- }
-
- bool signaled = true;
-
- if (indefinite)
- {
- foreach (MTLCommandBuffer fence in fences)
- {
- fence.WaitUntilCompleted();
- }
- }
- else
- {
- foreach (MTLCommandBuffer fence in fences)
- {
- if (fence.Status != MTLCommandBufferStatus.Completed)
- {
- signaled = false;
- }
- }
- }
-
- for (int i = 0; i < fenceCount; i++)
- {
- fenceHolders[i].Put();
- }
-
- return signaled;
- }
-
- ///
- /// Gets fences to wait for.
- ///
- /// Span to store fences in
- /// Number of fences placed in storage
- private int GetFences(Span storage)
- {
- int count = 0;
-
- for (int i = 0; i < _fences.Length; i++)
- {
- FenceHolder fence = _fences[i];
-
- if (fence != null)
- {
- storage[count++] = fence;
- }
- }
-
- return count;
- }
-
- ///
- /// Gets fences to wait for use of a given buffer region.
- ///
- /// Span to store overlapping fences in
- /// Offset of the range
- /// Size of the range in bytes
- /// Number of fences for the specified region placed in storage
- private int GetOverlappingFences(Span storage, int offset, int size)
- {
- int count = 0;
-
- for (int i = 0; i < _fences.Length; i++)
- {
- FenceHolder fence = _fences[i];
-
- if (fence != null && _bufferUsageBitmap.OverlapsWith(i, offset, size))
- {
- storage[count++] = fence;
- }
- }
-
- return count;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/PersistentFlushBuffer.cs b/src/Ryujinx.Graphics.Metal/PersistentFlushBuffer.cs
deleted file mode 100644
index fc79a40a9..000000000
--- a/src/Ryujinx.Graphics.Metal/PersistentFlushBuffer.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- internal class PersistentFlushBuffer : IDisposable
- {
- private readonly MetalRenderer _renderer;
-
- private BufferHolder _flushStorage;
-
- public PersistentFlushBuffer(MetalRenderer renderer)
- {
- _renderer = renderer;
- }
-
- private BufferHolder ResizeIfNeeded(int size)
- {
- BufferHolder flushStorage = _flushStorage;
-
- if (flushStorage == null || size > _flushStorage.Size)
- {
- flushStorage?.Dispose();
-
- flushStorage = _renderer.BufferManager.Create(size);
- _flushStorage = flushStorage;
- }
-
- return flushStorage;
- }
-
- public Span GetBufferData(CommandBufferPool cbp, BufferHolder buffer, int offset, int size)
- {
- BufferHolder flushStorage = ResizeIfNeeded(size);
- Auto srcBuffer;
-
- using (CommandBufferScoped cbs = cbp.Rent())
- {
- srcBuffer = buffer.GetBuffer();
- Auto dstBuffer = flushStorage.GetBuffer();
-
- if (srcBuffer.TryIncrementReferenceCount())
- {
- BufferHolder.Copy(cbs, srcBuffer, dstBuffer, offset, 0, size, registerSrcUsage: false);
- }
- else
- {
- // Source buffer is no longer alive, don't copy anything to flush storage.
- srcBuffer = null;
- }
- }
-
- flushStorage.WaitForFences();
- srcBuffer?.DecrementReferenceCount();
- return flushStorage.GetDataStorage(0, size);
- }
-
- public Span GetTextureData(CommandBufferPool cbp, Texture view, int size)
- {
- TextureCreateInfo info = view.Info;
-
- BufferHolder flushStorage = ResizeIfNeeded(size);
-
- using (CommandBufferScoped cbs = cbp.Rent())
- {
- MTLBuffer buffer = flushStorage.GetBuffer().Get(cbs).Value;
- MTLTexture image = view.GetHandle();
-
- view.CopyFromOrToBuffer(cbs, buffer, image, size, true, 0, 0, info.GetLayers(), info.Levels, singleSlice: false);
- }
-
- flushStorage.WaitForFences();
- return flushStorage.GetDataStorage(0, size);
- }
-
- public Span GetTextureData(CommandBufferPool cbp, Texture view, int size, int layer, int level)
- {
- BufferHolder flushStorage = ResizeIfNeeded(size);
-
- using (CommandBufferScoped cbs = cbp.Rent())
- {
- MTLBuffer buffer = flushStorage.GetBuffer().Get(cbs).Value;
- MTLTexture image = view.GetHandle();
-
- view.CopyFromOrToBuffer(cbs, buffer, image, size, true, layer, level, 1, 1, singleSlice: true);
- }
-
- flushStorage.WaitForFences();
- return flushStorage.GetDataStorage(0, size);
- }
-
- public void Dispose()
- {
- _flushStorage.Dispose();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs
deleted file mode 100644
index aebcb5493..000000000
--- a/src/Ryujinx.Graphics.Metal/Pipeline.cs
+++ /dev/null
@@ -1,877 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader;
-using SharpMetal.Foundation;
-using SharpMetal.Metal;
-using SharpMetal.QuartzCore;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- public enum EncoderType
- {
- Blit,
- Compute,
- Render,
- None
- }
-
- [SupportedOSPlatform("macos")]
- class Pipeline : IPipeline, IEncoderFactory, IDisposable
- {
- private const ulong MinByteWeightForFlush = 256 * 1024 * 1024; // MiB
-
- private readonly MTLDevice _device;
- private readonly MetalRenderer _renderer;
- private EncoderStateManager _encoderStateManager;
- private ulong _byteWeight;
-
- public MTLCommandBuffer CommandBuffer;
-
- public IndexBufferPattern QuadsToTrisPattern;
- public IndexBufferPattern TriFanToTrisPattern;
-
- internal CommandBufferScoped? PreloadCbs { get; private set; }
- internal CommandBufferScoped Cbs { get; private set; }
- internal CommandBufferEncoder Encoders => Cbs.Encoders;
- internal EncoderType CurrentEncoderType => Encoders.CurrentEncoderType;
-
- public Pipeline(MTLDevice device, MetalRenderer renderer)
- {
- _device = device;
- _renderer = renderer;
-
- renderer.CommandBufferPool.Initialize(this);
-
- CommandBuffer = (Cbs = _renderer.CommandBufferPool.Rent()).CommandBuffer;
- }
-
- internal void InitEncoderStateManager(BufferManager bufferManager)
- {
- _encoderStateManager = new EncoderStateManager(_device, bufferManager, this);
-
- QuadsToTrisPattern = new IndexBufferPattern(_renderer, 4, 6, 0, [0, 1, 2, 0, 2, 3], 4, false);
- TriFanToTrisPattern = new IndexBufferPattern(_renderer, 3, 3, 2, [int.MinValue, -1, 0], 1, true);
- }
-
- public EncoderState SwapState(EncoderState state, DirtyFlags flags = DirtyFlags.All, bool endRenderPass = true)
- {
- if (endRenderPass && CurrentEncoderType == EncoderType.Render)
- {
- EndCurrentPass();
- }
-
- return _encoderStateManager.SwapState(state, flags);
- }
-
- public PredrawState SavePredrawState()
- {
- return _encoderStateManager.SavePredrawState();
- }
-
- public void RestorePredrawState(PredrawState state)
- {
- _encoderStateManager.RestorePredrawState(state);
- }
-
- public void SetClearLoadAction(bool clear)
- {
- _encoderStateManager.SetClearLoadAction(clear);
- }
-
- public MTLRenderCommandEncoder GetOrCreateRenderEncoder(bool forDraw = false)
- {
- // Mark all state as dirty to ensure it is set on the new encoder
- if (Cbs.Encoders.CurrentEncoderType != EncoderType.Render)
- {
- _encoderStateManager.SignalRenderDirty();
- }
-
- if (forDraw)
- {
- _encoderStateManager.RenderResourcesPrepass();
- }
-
- MTLRenderCommandEncoder renderCommandEncoder = Cbs.Encoders.EnsureRenderEncoder();
-
- if (forDraw)
- {
- _encoderStateManager.RebindRenderState(renderCommandEncoder);
- }
-
- return renderCommandEncoder;
- }
-
- public MTLBlitCommandEncoder GetOrCreateBlitEncoder()
- {
- return Cbs.Encoders.EnsureBlitEncoder();
- }
-
- public MTLComputeCommandEncoder GetOrCreateComputeEncoder(bool forDispatch = false)
- {
- // Mark all state as dirty to ensure it is set on the new encoder
- if (Cbs.Encoders.CurrentEncoderType != EncoderType.Compute)
- {
- _encoderStateManager.SignalComputeDirty();
- }
-
- if (forDispatch)
- {
- _encoderStateManager.ComputeResourcesPrepass();
- }
-
- MTLComputeCommandEncoder computeCommandEncoder = Cbs.Encoders.EnsureComputeEncoder();
-
- if (forDispatch)
- {
- _encoderStateManager.RebindComputeState(computeCommandEncoder);
- }
-
- return computeCommandEncoder;
- }
-
- public void EndCurrentPass()
- {
- Cbs.Encoders.EndCurrentPass();
- }
-
- public MTLRenderCommandEncoder CreateRenderCommandEncoder()
- {
- return _encoderStateManager.CreateRenderCommandEncoder();
- }
-
- public MTLComputeCommandEncoder CreateComputeCommandEncoder()
- {
- return _encoderStateManager.CreateComputeCommandEncoder();
- }
-
- public void Present(CAMetalDrawable drawable, Texture src, Extents2D srcRegion, Extents2D dstRegion, bool isLinear)
- {
- // TODO: Clean this up
- TextureCreateInfo textureInfo = new((int)drawable.Texture.Width, (int)drawable.Texture.Height, (int)drawable.Texture.Depth, (int)drawable.Texture.MipmapLevelCount, (int)drawable.Texture.SampleCount, 0, 0, 0, Format.B8G8R8A8Unorm, 0, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha);
- Texture dst = new(_device, _renderer, this, textureInfo, drawable.Texture, 0, 0);
-
- _renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, isLinear, true);
-
- EndCurrentPass();
-
- Cbs.CommandBuffer.PresentDrawable(drawable);
-
- FlushCommandsImpl();
-
- // TODO: Auto flush counting
- _renderer.SyncManager.GetAndResetWaitTicks();
-
- // Cleanup
- dst.Dispose();
- }
-
- public CommandBufferScoped GetPreloadCommandBuffer()
- {
- PreloadCbs ??= _renderer.CommandBufferPool.Rent();
-
- return PreloadCbs.Value;
- }
-
- public void FlushCommandsIfWeightExceeding(IAuto disposedResource, ulong byteWeight)
- {
- bool usedByCurrentCb = disposedResource.HasCommandBufferDependency(Cbs);
-
- if (PreloadCbs != null && !usedByCurrentCb)
- {
- usedByCurrentCb = disposedResource.HasCommandBufferDependency(PreloadCbs.Value);
- }
-
- if (usedByCurrentCb)
- {
- // Since we can only free memory after the command buffer that uses a given resource was executed,
- // keeping the command buffer might cause a high amount of memory to be in use.
- // To prevent that, we force submit command buffers if the memory usage by resources
- // in use by the current command buffer is above a given limit, and those resources were disposed.
- _byteWeight += byteWeight;
-
- if (_byteWeight >= MinByteWeightForFlush)
- {
- FlushCommandsImpl();
- }
- }
- }
-
- public void FlushCommandsImpl()
- {
- EndCurrentPass();
-
- _byteWeight = 0;
-
- if (PreloadCbs != null)
- {
- PreloadCbs.Value.Dispose();
- PreloadCbs = null;
- }
-
- CommandBuffer = (Cbs = _renderer.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
- _renderer.RegisterFlush();
- }
-
- public void DirtyTextures()
- {
- _encoderStateManager.DirtyTextures();
- }
-
- public void DirtyImages()
- {
- _encoderStateManager.DirtyImages();
- }
-
- public void Blit(
- Texture src,
- Texture dst,
- Extents2D srcRegion,
- Extents2D dstRegion,
- bool isDepthOrStencil,
- bool linearFilter)
- {
- if (isDepthOrStencil)
- {
- _renderer.HelperShader.BlitDepthStencil(Cbs, src, dst, srcRegion, dstRegion);
- }
- else
- {
- _renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, linearFilter);
- }
- }
-
- public void Barrier()
- {
- switch (CurrentEncoderType)
- {
- case EncoderType.Render:
- {
- MTLBarrierScope scope = MTLBarrierScope.Buffers | MTLBarrierScope.Textures | MTLBarrierScope.RenderTargets;
- MTLRenderStages stages = MTLRenderStages.RenderStageVertex | MTLRenderStages.RenderStageFragment;
- Encoders.RenderEncoder.MemoryBarrier(scope, stages, stages);
- break;
- }
- case EncoderType.Compute:
- {
- MTLBarrierScope scope = MTLBarrierScope.Buffers | MTLBarrierScope.Textures | MTLBarrierScope.RenderTargets;
- Encoders.ComputeEncoder.MemoryBarrier(scope);
- break;
- }
- }
- }
-
- public void ClearBuffer(BufferHandle destination, int offset, int size, uint value)
- {
- MTLBlitCommandEncoder blitCommandEncoder = GetOrCreateBlitEncoder();
-
- MTLBuffer mtlBuffer = _renderer.BufferManager.GetBuffer(destination, offset, size, true).Get(Cbs, offset, size, true).Value;
-
- // Might need a closer look, range's count, lower, and upper bound
- // must be a multiple of 4
- blitCommandEncoder.FillBuffer(mtlBuffer,
- new NSRange
- {
- location = (ulong)offset,
- length = (ulong)size
- },
- (byte)value);
- }
-
- public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color)
- {
- float[] colors = [color.Red, color.Green, color.Blue, color.Alpha];
- Texture dst = _encoderStateManager.RenderTargets[index];
-
- // TODO: Remove workaround for Wonder which has an invalid texture due to unsupported format
- if (dst == null)
- {
- Logger.Warning?.PrintMsg(LogClass.Gpu, "Attempted to clear invalid render target!");
- return;
- }
-
- _renderer.HelperShader.ClearColor(index, colors, componentMask, dst.Width, dst.Height, dst.Info.Format);
- }
-
- public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
- {
- Texture depthStencil = _encoderStateManager.DepthStencil;
-
- if (depthStencil == null)
- {
- return;
- }
-
- _renderer.HelperShader.ClearDepthStencil(depthValue, depthMask, stencilValue, stencilMask, depthStencil.Width, depthStencil.Height);
- }
-
- public void CommandBufferBarrier()
- {
- Barrier();
- }
-
- public void CopyBuffer(BufferHandle src, BufferHandle dst, int srcOffset, int dstOffset, int size)
- {
- Auto srcBuffer = _renderer.BufferManager.GetBuffer(src, srcOffset, size, false);
- Auto dstBuffer = _renderer.BufferManager.GetBuffer(dst, dstOffset, size, true);
-
- BufferHolder.Copy(Cbs, srcBuffer, dstBuffer, srcOffset, dstOffset, size);
- }
-
- public void PushDebugGroup(string name)
- {
- MTLCommandEncoder? encoder = Encoders.CurrentEncoder;
- NSString debugGroupName = StringHelper.NSString(name);
-
- if (encoder == null)
- {
- return;
- }
-
- switch (Encoders.CurrentEncoderType)
- {
- case EncoderType.Render:
- encoder.Value.PushDebugGroup(debugGroupName);
- break;
- case EncoderType.Blit:
- encoder.Value.PushDebugGroup(debugGroupName);
- break;
- case EncoderType.Compute:
- encoder.Value.PushDebugGroup(debugGroupName);
- break;
- }
- }
-
- public void PopDebugGroup()
- {
- MTLCommandEncoder? encoder = Encoders.CurrentEncoder;
-
- if (encoder == null)
- {
- return;
- }
-
- switch (Encoders.CurrentEncoderType)
- {
- case EncoderType.Render:
- encoder.Value.PopDebugGroup();
- break;
- case EncoderType.Blit:
- encoder.Value.PopDebugGroup();
- break;
- case EncoderType.Compute:
- encoder.Value.PopDebugGroup();
- break;
- }
- }
-
- public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
- {
- DispatchCompute(groupsX, groupsY, groupsZ, String.Empty);
- }
-
- public void DispatchCompute(int groupsX, int groupsY, int groupsZ, string debugGroupName)
- {
- MTLComputeCommandEncoder computeCommandEncoder = GetOrCreateComputeEncoder(true);
-
- ComputeSize localSize = _encoderStateManager.ComputeLocalSize;
-
- if (debugGroupName != String.Empty)
- {
- PushDebugGroup(debugGroupName);
- }
-
- computeCommandEncoder.DispatchThreadgroups(
- new MTLSize { width = (ulong)groupsX, height = (ulong)groupsY, depth = (ulong)groupsZ },
- new MTLSize { width = (ulong)localSize.X, height = (ulong)localSize.Y, depth = (ulong)localSize.Z });
-
- if (debugGroupName != String.Empty)
- {
- PopDebugGroup();
- }
- }
-
- public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
- {
- Draw(vertexCount, instanceCount, firstVertex, firstInstance, String.Empty);
- }
-
- public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance, string debugGroupName)
- {
- if (vertexCount == 0)
- {
- return;
- }
-
- MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
-
- if (TopologyUnsupported(_encoderStateManager.Topology))
- {
- IndexBufferPattern pattern = GetIndexBufferPattern();
-
- BufferHandle handle = pattern.GetRepeatingBuffer(vertexCount, out int indexCount);
- Auto buffer = _renderer.BufferManager.GetBuffer(handle, false);
- MTLBuffer mtlBuffer = buffer.Get(Cbs, 0, indexCount * sizeof(int)).Value;
-
- MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
-
- renderCommandEncoder.DrawIndexedPrimitives(
- primitiveType,
- (ulong)indexCount,
- MTLIndexType.UInt32,
- mtlBuffer,
- 0);
- }
- else
- {
- MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
-
- if (debugGroupName != String.Empty)
- {
- PushDebugGroup(debugGroupName);
- }
-
- renderCommandEncoder.DrawPrimitives(
- primitiveType,
- (ulong)firstVertex,
- (ulong)vertexCount,
- (ulong)instanceCount,
- (ulong)firstInstance);
-
- if (debugGroupName != String.Empty)
- {
- PopDebugGroup();
- }
- }
- }
-
- private IndexBufferPattern GetIndexBufferPattern()
- {
- return _encoderStateManager.Topology switch
- {
- PrimitiveTopology.Quads => QuadsToTrisPattern,
- PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => TriFanToTrisPattern,
- _ => throw new NotSupportedException($"Unsupported topology: {_encoderStateManager.Topology}"),
- };
- }
-
- private PrimitiveTopology TopologyRemap(PrimitiveTopology topology)
- {
- return topology switch
- {
- PrimitiveTopology.Quads => PrimitiveTopology.Triangles,
- PrimitiveTopology.QuadStrip => PrimitiveTopology.TriangleStrip,
- PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => PrimitiveTopology.Triangles,
- _ => topology,
- };
- }
-
- private bool TopologyUnsupported(PrimitiveTopology topology)
- {
- return topology switch
- {
- PrimitiveTopology.Quads or PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => true,
- _ => false,
- };
- }
-
- public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
- {
- if (indexCount == 0)
- {
- return;
- }
-
- MTLBuffer mtlBuffer;
- int offset;
- MTLIndexType type;
- int finalIndexCount = indexCount;
-
- MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
-
- if (TopologyUnsupported(_encoderStateManager.Topology))
- {
- IndexBufferPattern pattern = GetIndexBufferPattern();
- int convertedCount = pattern.GetConvertedCount(indexCount);
-
- finalIndexCount = convertedCount;
-
- (mtlBuffer, offset, type) = _encoderStateManager.IndexBuffer.GetConvertedIndexBuffer(_renderer, Cbs, firstIndex, indexCount, convertedCount, pattern);
- }
- else
- {
- (mtlBuffer, offset, type) = _encoderStateManager.IndexBuffer.GetIndexBuffer(_renderer, Cbs);
- }
-
- if (mtlBuffer.NativePtr != IntPtr.Zero)
- {
- MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
-
- renderCommandEncoder.DrawIndexedPrimitives(
- primitiveType,
- (ulong)finalIndexCount,
- type,
- mtlBuffer,
- (ulong)offset,
- (ulong)instanceCount,
- firstVertex,
- (ulong)firstInstance);
- }
- }
-
- public void DrawIndexedIndirect(BufferRange indirectBuffer)
- {
- DrawIndexedIndirectOffset(indirectBuffer);
- }
-
- public void DrawIndexedIndirectOffset(BufferRange indirectBuffer, int offset = 0)
- {
- // TODO: Reindex unsupported topologies
- if (TopologyUnsupported(_encoderStateManager.Topology))
- {
- Logger.Warning?.Print(LogClass.Gpu, $"Drawing indexed with unsupported topology: {_encoderStateManager.Topology}");
- }
-
- MTLBuffer buffer = _renderer.BufferManager
- .GetBuffer(indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
- .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
-
- MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
-
- (MTLBuffer indexBuffer, int indexOffset, MTLIndexType type) = _encoderStateManager.IndexBuffer.GetIndexBuffer(_renderer, Cbs);
-
- if (indexBuffer.NativePtr != IntPtr.Zero && buffer.NativePtr != IntPtr.Zero)
- {
- MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
-
- renderCommandEncoder.DrawIndexedPrimitives(
- primitiveType,
- type,
- indexBuffer,
- (ulong)indexOffset,
- buffer,
- (ulong)(indirectBuffer.Offset + offset));
- }
- }
-
- public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
- {
- for (int i = 0; i < maxDrawCount; i++)
- {
- DrawIndexedIndirectOffset(indirectBuffer, stride * i);
- }
- }
-
- public void DrawIndirect(BufferRange indirectBuffer)
- {
- DrawIndirectOffset(indirectBuffer);
- }
-
- public void DrawIndirectOffset(BufferRange indirectBuffer, int offset = 0)
- {
- if (TopologyUnsupported(_encoderStateManager.Topology))
- {
- // TODO: Reindex unsupported topologies
- Logger.Warning?.Print(LogClass.Gpu, $"Drawing indirect with unsupported topology: {_encoderStateManager.Topology}");
- }
-
- MTLBuffer buffer = _renderer.BufferManager
- .GetBuffer(indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
- .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
-
- MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
- MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
-
- renderCommandEncoder.DrawPrimitives(
- primitiveType,
- buffer,
- (ulong)(indirectBuffer.Offset + offset));
- }
-
- public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
- {
- for (int i = 0; i < maxDrawCount; i++)
- {
- DrawIndirectOffset(indirectBuffer, stride * i);
- }
- }
-
- public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
- {
- _renderer.HelperShader.DrawTexture(texture, sampler, srcRegion, dstRegion);
- }
-
- public void SetAlphaTest(bool enable, float reference, CompareOp op)
- {
- // This is currently handled using shader specialization, as Metal does not support alpha test.
- // In the future, we may want to use this to write the reference value into the support buffer,
- // to avoid creating one version of the shader per reference value used.
- }
-
- public void SetBlendState(AdvancedBlendDescriptor blend)
- {
- // Metal does not support advanced blend.
- }
-
- public void SetBlendState(int index, BlendDescriptor blend)
- {
- _encoderStateManager.UpdateBlendDescriptors(index, blend);
- }
-
- public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
- {
- if (enables == 0)
- {
- _encoderStateManager.UpdateDepthBias(0, 0, 0);
- }
- else
- {
- _encoderStateManager.UpdateDepthBias(units, factor, clamp);
- }
- }
-
- public void SetDepthClamp(bool clamp)
- {
- _encoderStateManager.UpdateDepthClamp(clamp);
- }
-
- public void SetDepthMode(DepthMode mode)
- {
- // Metal does not support depth clip control.
- }
-
- public void SetDepthTest(DepthTestDescriptor depthTest)
- {
- _encoderStateManager.UpdateDepthState(depthTest);
- }
-
- public void SetFaceCulling(bool enable, Face face)
- {
- _encoderStateManager.UpdateCullMode(enable, face);
- }
-
- public void SetFrontFace(FrontFace frontFace)
- {
- _encoderStateManager.UpdateFrontFace(frontFace);
- }
-
- public void SetIndexBuffer(BufferRange buffer, IndexType type)
- {
- _encoderStateManager.UpdateIndexBuffer(buffer, type);
- }
-
- public void SetImage(ShaderStage stage, int binding, ITexture image)
- {
- if (image is TextureBase img)
- {
- _encoderStateManager.UpdateImage(stage, binding, img);
- }
- }
-
- public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
- {
- if (array is ImageArray imageArray)
- {
- _encoderStateManager.UpdateImageArray(stage, binding, imageArray);
- }
- }
-
- public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
- {
- if (array is ImageArray imageArray)
- {
- _encoderStateManager.UpdateImageArraySeparate(stage, setIndex, imageArray);
- }
- }
-
- public void SetLineParameters(float width, bool smooth)
- {
- // Metal does not support wide-lines.
- }
-
- public void SetLogicOpState(bool enable, LogicalOp op)
- {
- _encoderStateManager.UpdateLogicOpState(enable, op);
- }
-
- public void SetMultisampleState(MultisampleDescriptor multisample)
- {
- _encoderStateManager.UpdateMultisampleState(multisample);
- }
-
- public void SetPatchParameters(int vertices, ReadOnlySpan defaultOuterLevel, ReadOnlySpan defaultInnerLevel)
- {
- Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
- }
-
- public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
- {
- Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
- }
-
- public void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode)
- {
- // Metal does not support polygon mode.
- }
-
- public void SetPrimitiveRestart(bool enable, int index)
- {
- // Always active for LineStrip and TriangleStrip
- // https://github.com/gpuweb/gpuweb/issues/1220#issuecomment-732483263
- // https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515520-drawindexedprimitives
- // https://stackoverflow.com/questions/70813665/how-to-render-multiple-trianglestrips-using-metal
-
- // Emulating disabling this is very difficult. It's unlikely for an index buffer to use the largest possible index,
- // so it's fine nearly all of the time.
- }
-
- public void SetPrimitiveTopology(PrimitiveTopology topology)
- {
- _encoderStateManager.UpdatePrimitiveTopology(topology);
- }
-
- public void SetProgram(IProgram program)
- {
- _encoderStateManager.UpdateProgram(program);
- }
-
- public void SetRasterizerDiscard(bool discard)
- {
- _encoderStateManager.UpdateRasterizerDiscard(discard);
- }
-
- public void SetRenderTargetColorMasks(ReadOnlySpan componentMask)
- {
- _encoderStateManager.UpdateRenderTargetColorMasks(componentMask);
- }
-
- public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
- {
- _encoderStateManager.UpdateRenderTargets(colors, depthStencil);
- }
-
- public void SetScissors(ReadOnlySpan> regions)
- {
- _encoderStateManager.UpdateScissors(regions);
- }
-
- public void SetStencilTest(StencilTestDescriptor stencilTest)
- {
- _encoderStateManager.UpdateStencilState(stencilTest);
- }
-
- public void SetUniformBuffers(ReadOnlySpan buffers)
- {
- _encoderStateManager.UpdateUniformBuffers(buffers);
- }
-
- public void SetStorageBuffers(ReadOnlySpan buffers)
- {
- _encoderStateManager.UpdateStorageBuffers(buffers);
- }
-
- internal void SetStorageBuffers(int first, ReadOnlySpan> buffers)
- {
- _encoderStateManager.UpdateStorageBuffers(first, buffers);
- }
-
- public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
- {
- if (texture is TextureBase tex)
- {
- if (sampler == null || sampler is SamplerHolder)
- {
- _encoderStateManager.UpdateTextureAndSampler(stage, binding, tex, (SamplerHolder)sampler);
- }
- }
- }
-
- public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
- {
- if (array is TextureArray textureArray)
- {
- _encoderStateManager.UpdateTextureArray(stage, binding, textureArray);
- }
- }
-
- public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
- {
- if (array is TextureArray textureArray)
- {
- _encoderStateManager.UpdateTextureArraySeparate(stage, setIndex, textureArray);
- }
- }
-
- public void SetUserClipDistance(int index, bool enableClip)
- {
- // TODO. Same as Vulkan
- }
-
- public void SetVertexAttribs(ReadOnlySpan vertexAttribs)
- {
- _encoderStateManager.UpdateVertexAttribs(vertexAttribs);
- }
-
- public void SetVertexBuffers(ReadOnlySpan vertexBuffers)
- {
- _encoderStateManager.UpdateVertexBuffers(vertexBuffers);
- }
-
- public void SetViewports(ReadOnlySpan viewports)
- {
- _encoderStateManager.UpdateViewports(viewports);
- }
-
- public void TextureBarrier()
- {
- if (CurrentEncoderType == EncoderType.Render)
- {
- Encoders.RenderEncoder.MemoryBarrier(MTLBarrierScope.Textures, MTLRenderStages.RenderStageFragment, MTLRenderStages.RenderStageFragment);
- }
- }
-
- public void TextureBarrierTiled()
- {
- TextureBarrier();
- }
-
- public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
- {
- // TODO: Implementable via indirect draw commands
- return false;
- }
-
- public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
- {
- // TODO: Implementable via indirect draw commands
- return false;
- }
-
- public void EndHostConditionalRendering()
- {
- // TODO: Implementable via indirect draw commands
- }
-
- public void BeginTransformFeedback(PrimitiveTopology topology)
- {
- // Metal does not support transform feedback.
- }
-
- public void EndTransformFeedback()
- {
- // Metal does not support transform feedback.
- }
-
- public void SetTransformFeedbackBuffers(ReadOnlySpan buffers)
- {
- // Metal does not support transform feedback.
- }
-
- public void Dispose()
- {
- EndCurrentPass();
- _encoderStateManager.Dispose();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Program.cs b/src/Ryujinx.Graphics.Metal/Program.cs
deleted file mode 100644
index 721ee56a7..000000000
--- a/src/Ryujinx.Graphics.Metal/Program.cs
+++ /dev/null
@@ -1,286 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader;
-using SharpMetal.Foundation;
-using SharpMetal.Metal;
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class Program : IProgram
- {
- private ProgramLinkStatus _status;
- private readonly ShaderSource[] _shaders;
- private readonly GCHandle[] _handles;
- private int _successCount;
-
- private readonly MetalRenderer _renderer;
-
- public MTLFunction VertexFunction;
- public MTLFunction FragmentFunction;
- public MTLFunction ComputeFunction;
- public ComputeSize ComputeLocalSize { get; }
-
- private HashTableSlim _graphicsPipelineCache;
- private MTLComputePipelineState? _computePipelineCache;
- private bool _firstBackgroundUse;
-
- public ResourceBindingSegment[][] BindingSegments { get; }
- // Argument buffer sizes for Vertex or Compute stages
- public int[] ArgumentBufferSizes { get; }
- // Argument buffer sizes for Fragment stage
- public int[] FragArgumentBufferSizes { get; }
-
- public Program(
- MetalRenderer renderer,
- MTLDevice device,
- ShaderSource[] shaders,
- ResourceLayout resourceLayout,
- ComputeSize computeLocalSize = default)
- {
- _renderer = renderer;
- renderer.Programs.Add(this);
-
- ComputeLocalSize = computeLocalSize;
- _shaders = shaders;
- _handles = new GCHandle[_shaders.Length];
-
- _status = ProgramLinkStatus.Incomplete;
-
- for (int i = 0; i < _shaders.Length; i++)
- {
- ShaderSource shader = _shaders[i];
-
- using MTLCompileOptions compileOptions = new()
- {
- PreserveInvariance = true,
- LanguageVersion = MTLLanguageVersion.Version31,
- };
- int index = i;
-
- _handles[i] = device.NewLibrary(StringHelper.NSString(shader.Code), compileOptions, (library, error) => CompilationResultHandler(library, error, index));
- }
-
- (BindingSegments, ArgumentBufferSizes, FragArgumentBufferSizes) = BuildBindingSegments(resourceLayout.SetUsages);
- }
-
- public void CompilationResultHandler(MTLLibrary library, NSError error, int index)
- {
- ShaderSource shader = _shaders[index];
-
- if (_handles[index].IsAllocated)
- {
- _handles[index].Free();
- }
-
- if (error != IntPtr.Zero)
- {
- Logger.Warning?.PrintMsg(LogClass.Gpu, shader.Code);
- Logger.Warning?.Print(LogClass.Gpu, $"{shader.Stage} shader linking failed: \n{StringHelper.String(error.LocalizedDescription)}");
- _status = ProgramLinkStatus.Failure;
- return;
- }
-
- switch (shader.Stage)
- {
- case ShaderStage.Compute:
- ComputeFunction = library.NewFunction(StringHelper.NSString("kernelMain"));
- break;
- case ShaderStage.Vertex:
- VertexFunction = library.NewFunction(StringHelper.NSString("vertexMain"));
- break;
- case ShaderStage.Fragment:
- FragmentFunction = library.NewFunction(StringHelper.NSString("fragmentMain"));
- break;
- default:
- Logger.Warning?.Print(LogClass.Gpu, $"Cannot handle stage {shader.Stage}!");
- break;
- }
-
- _successCount++;
-
- if (_successCount >= _shaders.Length && _status != ProgramLinkStatus.Failure)
- {
- _status = ProgramLinkStatus.Success;
- }
- }
-
- private static (ResourceBindingSegment[][], int[], int[]) BuildBindingSegments(ReadOnlyCollection setUsages)
- {
- ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][];
- int[] argBufferSizes = new int[setUsages.Count];
- int[] fragArgBufferSizes = new int[setUsages.Count];
-
- for (int setIndex = 0; setIndex < setUsages.Count; setIndex++)
- {
- List currentSegments = [];
-
- ResourceUsage currentUsage = default;
- int currentCount = 0;
-
- for (int index = 0; index < setUsages[setIndex].Usages.Count; index++)
- {
- ResourceUsage usage = setUsages[setIndex].Usages[index];
-
- if (currentUsage.Binding + currentCount != usage.Binding ||
- currentUsage.Type != usage.Type ||
- currentUsage.Stages != usage.Stages ||
- currentUsage.ArrayLength > 1 ||
- usage.ArrayLength > 1)
- {
- if (currentCount != 0)
- {
- currentSegments.Add(new ResourceBindingSegment(
- currentUsage.Binding,
- currentCount,
- currentUsage.Type,
- currentUsage.Stages,
- currentUsage.ArrayLength > 1));
-
- int size = currentCount * ResourcePointerSize(currentUsage.Type);
- if (currentUsage.Stages.HasFlag(ResourceStages.Fragment))
- {
- fragArgBufferSizes[setIndex] += size;
- }
-
- if (currentUsage.Stages.HasFlag(ResourceStages.Vertex) ||
- currentUsage.Stages.HasFlag(ResourceStages.Compute))
- {
- argBufferSizes[setIndex] += size;
- }
- }
-
- currentUsage = usage;
- currentCount = usage.ArrayLength;
- }
- else
- {
- currentCount++;
- }
- }
-
- if (currentCount != 0)
- {
- currentSegments.Add(new ResourceBindingSegment(
- currentUsage.Binding,
- currentCount,
- currentUsage.Type,
- currentUsage.Stages,
- currentUsage.ArrayLength > 1));
-
- int size = currentCount * ResourcePointerSize(currentUsage.Type);
- if (currentUsage.Stages.HasFlag(ResourceStages.Fragment))
- {
- fragArgBufferSizes[setIndex] += size;
- }
-
- if (currentUsage.Stages.HasFlag(ResourceStages.Vertex) ||
- currentUsage.Stages.HasFlag(ResourceStages.Compute))
- {
- argBufferSizes[setIndex] += size;
- }
- }
-
- segments[setIndex] = currentSegments.ToArray();
- }
-
- return (segments, argBufferSizes, fragArgBufferSizes);
- }
-
- private static int ResourcePointerSize(ResourceType type)
- {
- return (type == ResourceType.TextureAndSampler ? 2 : 1);
- }
-
- public ProgramLinkStatus CheckProgramLink(bool blocking)
- {
- if (blocking)
- {
- while (_status == ProgramLinkStatus.Incomplete)
- { }
-
- return _status;
- }
-
- return _status;
- }
-
- public byte[] GetBinary()
- {
- return [];
- }
-
- public void AddGraphicsPipeline(ref PipelineUid key, MTLRenderPipelineState pipeline)
- {
- (_graphicsPipelineCache ??= new()).Add(ref key, pipeline);
- }
-
- public void AddComputePipeline(MTLComputePipelineState pipeline)
- {
- _computePipelineCache = pipeline;
- }
-
- public bool TryGetGraphicsPipeline(ref PipelineUid key, out MTLRenderPipelineState pipeline)
- {
- if (_graphicsPipelineCache == null)
- {
- pipeline = default;
- return false;
- }
-
- if (!_graphicsPipelineCache.TryGetValue(ref key, out pipeline))
- {
- if (_firstBackgroundUse)
- {
- Logger.Warning?.Print(LogClass.Gpu, "Background pipeline compile missed on draw - incorrect pipeline state?");
- _firstBackgroundUse = false;
- }
-
- return false;
- }
-
- _firstBackgroundUse = false;
-
- return true;
- }
-
- public bool TryGetComputePipeline(out MTLComputePipelineState pipeline)
- {
- if (_computePipelineCache.HasValue)
- {
- pipeline = _computePipelineCache.Value;
- return true;
- }
-
- pipeline = default;
- return false;
- }
-
- public void Dispose()
- {
- if (!_renderer.Programs.Remove(this))
- {
- return;
- }
-
- if (_graphicsPipelineCache != null)
- {
- foreach (MTLRenderPipelineState pipeline in _graphicsPipelineCache.Values)
- {
- pipeline.Dispose();
- }
- }
-
- _computePipelineCache?.Dispose();
-
- VertexFunction.Dispose();
- FragmentFunction.Dispose();
- ComputeFunction.Dispose();
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/ResourceBindingSegment.cs b/src/Ryujinx.Graphics.Metal/ResourceBindingSegment.cs
deleted file mode 100644
index 8e6d88c4b..000000000
--- a/src/Ryujinx.Graphics.Metal/ResourceBindingSegment.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Metal
-{
- readonly struct ResourceBindingSegment
- {
- public readonly int Binding;
- public readonly int Count;
- public readonly ResourceType Type;
- public readonly ResourceStages Stages;
- public readonly bool IsArray;
-
- public ResourceBindingSegment(int binding, int count, ResourceType type, ResourceStages stages, bool isArray)
- {
- Binding = binding;
- Count = count;
- Type = type;
- Stages = stages;
- IsArray = isArray;
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs b/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs
deleted file mode 100644
index 623f91612..000000000
--- a/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using System;
-using System.Collections.Generic;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class ResourceLayoutBuilder
- {
- private const int TotalSets = MetalRenderer.TotalSets;
-
- private readonly List[] _resourceDescriptors;
- private readonly List[] _resourceUsages;
-
- public ResourceLayoutBuilder()
- {
- _resourceDescriptors = new List[TotalSets];
- _resourceUsages = new List[TotalSets];
-
- for (int index = 0; index < TotalSets; index++)
- {
- _resourceDescriptors[index] = [];
- _resourceUsages[index] = [];
- }
- }
-
- public ResourceLayoutBuilder Add(ResourceStages stages, ResourceType type, int binding, bool write = false)
- {
- uint setIndex = type switch
- {
- ResourceType.UniformBuffer => Constants.ConstantBuffersSetIndex,
- ResourceType.StorageBuffer => Constants.StorageBuffersSetIndex,
- ResourceType.TextureAndSampler or ResourceType.BufferTexture => Constants.TexturesSetIndex,
- ResourceType.Image or ResourceType.BufferImage => Constants.ImagesSetIndex,
- _ => throw new ArgumentException($"Invalid resource type \"{type}\"."),
- };
-
- _resourceDescriptors[setIndex].Add(new ResourceDescriptor(binding, 1, type, stages));
- _resourceUsages[setIndex].Add(new ResourceUsage(binding, 1, type, stages, write));
-
- return this;
- }
-
- public ResourceLayout Build()
- {
- ResourceDescriptorCollection[] descriptors = new ResourceDescriptorCollection[TotalSets];
- ResourceUsageCollection[] usages = new ResourceUsageCollection[TotalSets];
-
- for (int index = 0; index < TotalSets; index++)
- {
- descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
- usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());
- }
-
- return new ResourceLayout(descriptors.AsReadOnly(), usages.AsReadOnly());
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj b/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj
deleted file mode 100644
index 364aa5a8b..000000000
--- a/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Ryujinx.Graphics.Metal/SamplerHolder.cs b/src/Ryujinx.Graphics.Metal/SamplerHolder.cs
deleted file mode 100644
index a448b26fe..000000000
--- a/src/Ryujinx.Graphics.Metal/SamplerHolder.cs
+++ /dev/null
@@ -1,90 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using SharpMetal.Metal;
-using System;
-using System.Runtime.Versioning;
-
-namespace Ryujinx.Graphics.Metal
-{
- [SupportedOSPlatform("macos")]
- class SamplerHolder : ISampler
- {
- private readonly MetalRenderer _renderer;
- private readonly Auto _sampler;
-
- public SamplerHolder(MetalRenderer renderer, MTLDevice device, SamplerCreateInfo info)
- {
- _renderer = renderer;
-
- renderer.Samplers.Add(this);
-
- (MTLSamplerMinMagFilter minFilter, MTLSamplerMipFilter mipFilter) = info.MinFilter.Convert();
-
- MTLSamplerBorderColor borderColor = GetConstrainedBorderColor(info.BorderColor, out _);
-
- using MTLSamplerDescriptor descriptor = new()
- {
- BorderColor = borderColor,
- MinFilter = minFilter,
- MagFilter = info.MagFilter.Convert(),
- MipFilter = mipFilter,
- CompareFunction = info.CompareOp.Convert(),
- LodMinClamp = info.MinLod,
- LodMaxClamp = info.MaxLod,
- LodAverage = false,
- MaxAnisotropy = Math.Max((uint)info.MaxAnisotropy, 1),
- SAddressMode = info.AddressU.Convert(),
- TAddressMode = info.AddressV.Convert(),
- RAddressMode = info.AddressP.Convert(),
- SupportArgumentBuffers = true
- };
-
- MTLSamplerState sampler = device.NewSamplerState(descriptor);
-
- _sampler = new Auto(new DisposableSampler(sampler));
- }
-
- private static MTLSamplerBorderColor GetConstrainedBorderColor(ColorF arbitraryBorderColor, out bool cantConstrain)
- {
- float r = arbitraryBorderColor.Red;
- float g = arbitraryBorderColor.Green;
- float b = arbitraryBorderColor.Blue;
- float a = arbitraryBorderColor.Alpha;
-
- if (r == 0f && g == 0f && b == 0f)
- {
- if (a == 1f)
- {
- cantConstrain = false;
- return MTLSamplerBorderColor.OpaqueBlack;
- }
-
- if (a == 0f)
- {
- cantConstrain = false;
- return MTLSamplerBorderColor.TransparentBlack;
- }
- }
- else if (r == 1f && g == 1f && b == 1f && a == 1f)
- {
- cantConstrain = false;
- return MTLSamplerBorderColor.OpaqueWhite;
- }
-
- cantConstrain = true;
- return MTLSamplerBorderColor.OpaqueBlack;
- }
-
- public Auto GetSampler()
- {
- return _sampler;
- }
-
- public void Dispose()
- {
- if (_renderer.Samplers.Remove(this))
- {
- _sampler.Dispose();
- }
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal b/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal
deleted file mode 100644
index 887878499..000000000
--- a/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal
+++ /dev/null
@@ -1,43 +0,0 @@
-#include
-
-using namespace metal;
-
-struct CopyVertexOut {
- float4 position [[position]];
- float2 uv;
-};
-
-struct TexCoords {
- float data[4];
-};
-
-struct ConstantBuffers {
- constant TexCoords* tex_coord;
-};
-
-struct Textures
-{
- texture2d texture;
- sampler sampler;
-};
-
-vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
- constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
- CopyVertexOut out;
-
- int low = vid & 1;
- int high = vid >> 1;
- out.uv.x = constant_buffers.tex_coord->data[low];
- out.uv.y = constant_buffers.tex_coord->data[2 + high];
- out.position.x = (float(low) - 0.5f) * 2.0f;
- out.position.y = (float(high) - 0.5f) * 2.0f;
- out.position.z = 0.0f;
- out.position.w = 1.0f;
-
- return out;
-}
-
-fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]],
- constant Textures &textures [[buffer(TEXTURES_INDEX)]]) {
- return textures.texture.sample(textures.sampler, in.uv);
-}
diff --git a/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal b/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal
deleted file mode 100644
index 1077b6cea..000000000
--- a/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal
+++ /dev/null
@@ -1,45 +0,0 @@
-#include
-
-using namespace metal;
-
-struct CopyVertexOut {
- float4 position [[position]];
- float2 uv;
-};
-
-struct TexCoords {
- float data[4];
-};
-
-struct ConstantBuffers {
- constant TexCoords* tex_coord;
-};
-
-struct Textures
-{
- texture2d_ms texture;
-};
-
-vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
- constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
- CopyVertexOut out;
-
- int low = vid & 1;
- int high = vid >> 1;
- out.uv.x = constant_buffers.tex_coord->data[low];
- out.uv.y = constant_buffers.tex_coord->data[2 + high];
- out.position.x = (float(low) - 0.5f) * 2.0f;
- out.position.y = (float(high) - 0.5f) * 2.0f;
- out.position.z = 0.0f;
- out.position.w = 1.0f;
-
- return out;
-}
-
-fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]],
- constant Textures &textures [[buffer(TEXTURES_INDEX)]],
- uint sample_id [[sample_id]]) {
- uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
- uint2 tex_coord = uint2(in.uv * float2(tex_size));
- return textures.texture.read(tex_coord, sample_id);
-}
diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal b/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal
deleted file mode 100644
index 1a7d2c574..000000000
--- a/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal
+++ /dev/null
@@ -1,72 +0,0 @@
-#include
-
-using namespace metal;
-
-struct StrideArguments {
- int4 data;
-};
-
-struct InData {
- uint8_t data[1];
-};
-
-struct OutData {
- uint8_t data[1];
-};
-
-struct ConstantBuffers {
- constant StrideArguments* stride_arguments;
-};
-
-struct StorageBuffers {
- device InData* in_data;
- device OutData* out_data;
-};
-
-kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]],
- device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
- uint3 thread_position_in_grid [[thread_position_in_grid]],
- uint3 threads_per_threadgroup [[threads_per_threadgroup]],
- uint3 threadgroups_per_grid [[threadgroups_per_grid]])
-{
- // Determine what slice of the stride copies this invocation will perform.
-
- int sourceStride = constant_buffers.stride_arguments->data.x;
- int targetStride = constant_buffers.stride_arguments->data.y;
- int bufferSize = constant_buffers.stride_arguments->data.z;
- int sourceOffset = constant_buffers.stride_arguments->data.w;
-
- int strideRemainder = targetStride - sourceStride;
- int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
-
- int copiesRequired = bufferSize / sourceStride;
-
- // Find the copies that this invocation should perform.
-
- // - Copies that all invocations perform.
- int allInvocationCopies = copiesRequired / invocations;
-
- // - Extra remainder copy that this invocation performs.
- int index = int(thread_position_in_grid.x);
- int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
-
- int copyCount = allInvocationCopies + extra;
-
- // Finally, get the starting offset. Make sure to count extra copies.
-
- int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
-
- int srcOffset = sourceOffset + startCopy * sourceStride;
- int dstOffset = startCopy * targetStride;
-
- // Perform the copies for this region
- for (int i = 0; i < copyCount; i++) {
- for (int j = 0; j < sourceStride; j++) {
- storage_buffers.out_data->data[dstOffset++] = storage_buffers.in_data->data[srcOffset++];
- }
-
- for (int j = 0; j < strideRemainder; j++) {
- storage_buffers.out_data->data[dstOffset++] = uint8_t(0);
- }
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal b/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal
deleted file mode 100644
index 46a57e035..000000000
--- a/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal
+++ /dev/null
@@ -1,38 +0,0 @@
-#include
-
-using namespace metal;
-
-struct VertexOut {
- float4 position [[position]];
-};
-
-struct ClearColor {
- FORMAT4 data;
-};
-
-struct ConstantBuffers {
- constant ClearColor* clear_color;
-};
-
-vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
- int low = vid & 1;
- int high = vid >> 1;
-
- VertexOut out;
-
- out.position.x = (float(low) - 0.5f) * 2.0f;
- out.position.y = (float(high) - 0.5f) * 2.0f;
- out.position.z = 0.0f;
- out.position.w = 1.0f;
-
- return out;
-}
-
-struct FragmentOut {
- FORMAT4 color [[color(COLOR_ATTACHMENT_INDEX)]];
-};
-
-fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
- constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
- return {constant_buffers.clear_color->data};
-}
diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ConvertD32S8ToD24S8.metal b/src/Ryujinx.Graphics.Metal/Shaders/ConvertD32S8ToD24S8.metal
deleted file mode 100644
index 870ac3d78..000000000
--- a/src/Ryujinx.Graphics.Metal/Shaders/ConvertD32S8ToD24S8.metal
+++ /dev/null
@@ -1,66 +0,0 @@
-#include
-
-using namespace metal;
-
-struct StrideArguments {
- int pixelCount;
- int dstStartOffset;
-};
-
-struct InData {
- uint data[1];
-};
-
-struct OutData {
- uint data[1];
-};
-
-struct ConstantBuffers {
- constant StrideArguments* stride_arguments;
-};
-
-struct StorageBuffers {
- device InData* in_data;
- device OutData* out_data;
-};
-
-kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]],
- device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
- uint3 thread_position_in_grid [[thread_position_in_grid]],
- uint3 threads_per_threadgroup [[threads_per_threadgroup]],
- uint3 threadgroups_per_grid [[threadgroups_per_grid]])
-{
- // Determine what slice of the stride copies this invocation will perform.
- int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
-
- int copiesRequired = constant_buffers.stride_arguments->pixelCount;
-
- // Find the copies that this invocation should perform.
-
- // - Copies that all invocations perform.
- int allInvocationCopies = copiesRequired / invocations;
-
- // - Extra remainder copy that this invocation performs.
- int index = int(thread_position_in_grid.x);
- int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
-
- int copyCount = allInvocationCopies + extra;
-
- // Finally, get the starting offset. Make sure to count extra copies.
-
- int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
-
- int srcOffset = startCopy * 2;
- int dstOffset = constant_buffers.stride_arguments->dstStartOffset + startCopy;
-
- // Perform the conversion for this region.
- for (int i = 0; i < copyCount; i++)
- {
- float depth = as_type(storage_buffers.in_data->data[srcOffset++]);
- uint stencil = storage_buffers.in_data->data[srcOffset++];
-
- uint rescaledDepth = uint(clamp(depth, 0.0, 1.0) * 16777215.0);
-
- storage_buffers.out_data->data[dstOffset++] = (rescaledDepth << 8) | (stencil & 0xff);
- }
-}
diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ConvertIndexBuffer.metal b/src/Ryujinx.Graphics.Metal/Shaders/ConvertIndexBuffer.metal
deleted file mode 100644
index c8fee5818..000000000
--- a/src/Ryujinx.Graphics.Metal/Shaders/ConvertIndexBuffer.metal
+++ /dev/null
@@ -1,59 +0,0 @@
-#include