From 4cd15cb1a68b5f6313ca6de7bafad1e1baaf79ad Mon Sep 17 00:00:00 2001 From: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com> Date: Wed, 31 Jul 2024 23:32:37 +0100 Subject: [PATCH] Shader Extra Set Support + Cleanup (#36) Separate samplers are now supported and arrays in constant sets are bound --- src/Ryujinx.Graphics.Metal/Constants.cs | 23 +- .../EncoderStateManager.cs | 313 +++++++++++++----- src/Ryujinx.Graphics.Metal/HelperShader.cs | 11 +- src/Ryujinx.Graphics.Metal/MetalRenderer.cs | 20 +- .../ResourceLayoutBuilder.cs | 10 +- src/Ryujinx.Graphics.Metal/Shaders/Blit.metal | 4 +- .../Shaders/BlitMs.metal | 2 +- .../Shaders/ChangeBufferStride.metal | 4 +- .../Shaders/ColorClear.metal | 2 +- .../Shaders/DepthBlit.metal | 2 +- .../Shaders/DepthBlitMs.metal | 2 +- .../Shaders/DepthStencilClear.metal | 2 +- .../Shaders/StencilBlit.metal | 2 +- .../Shaders/StencilBlitMs.metal | 2 +- src/Ryujinx.Graphics.Metal/TextureArray.cs | 10 + .../CodeGen/Msl/Declarations.cs | 128 ++++--- .../CodeGen/Msl/Defaults.cs | 20 +- .../CodeGen/Msl/Instructions/InstGenMemory.cs | 15 +- .../CodeGen/Msl/MslGenerator.cs | 19 +- src/Ryujinx.Graphics.Shader/SamplerType.cs | 2 +- 20 files changed, 412 insertions(+), 181 deletions(-) diff --git a/src/Ryujinx.Graphics.Metal/Constants.cs b/src/Ryujinx.Graphics.Metal/Constants.cs index 58735824d..133925e2d 100644 --- a/src/Ryujinx.Graphics.Metal/Constants.cs +++ b/src/Ryujinx.Graphics.Metal/Constants.cs @@ -2,7 +2,6 @@ namespace Ryujinx.Graphics.Metal { static class Constants { - // TODO: Check these values, these were largely copied from Vulkan public const int MaxShaderStages = 5; public const int MaxVertexBuffers = 16; public const int MaxUniformBuffersPerStage = 18; @@ -15,17 +14,25 @@ namespace Ryujinx.Graphics.Metal public const int MaxViewports = 16; // TODO: Check this value public const int MaxVertexAttributes = 31; - // TODO: Check this value - public const int MaxVertexLayouts = 31; public const int MinResourceAlignment = 16; // Must match constants set in shader generation - public const uint ZeroBufferIndex = 18; + public const uint ZeroBufferIndex = MaxVertexBuffers; + public const uint BaseSetIndex = MaxVertexBuffers + 1; - public const uint ConstantBuffersIndex = 20; - public const uint StorageBuffersIndex = 21; - public const uint TexturesIndex = 22; - public const uint ImagesIndex = 23; + 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/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs index 0f98496bc..41a4140fd 100644 --- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs +++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs @@ -57,11 +57,16 @@ namespace Ryujinx.Graphics.Metal _depthStencilCache.Dispose(); } + private readonly void SignalDirty(DirtyFlags flags) + { + _currentState.Dirty |= flags; + } + public EncoderState SwapState(EncoderState state, DirtyFlags flags = DirtyFlags.All) { _currentState = state ?? _mainState; - _currentState.Dirty |= flags; + SignalDirty(flags); return _mainState; } @@ -84,7 +89,7 @@ namespace Ryujinx.Graphics.Metal _currentState.Topology = state.Topology; _currentState.Viewports = state.Viewports; - _currentState.Dirty |= DirtyFlags.CullMode | DirtyFlags.DepthStencil | DirtyFlags.Viewports; + SignalDirty(DirtyFlags.CullMode | DirtyFlags.DepthStencil | DirtyFlags.Viewports); } public readonly void SetClearLoadAction(bool clear) @@ -94,12 +99,12 @@ namespace Ryujinx.Graphics.Metal public void DirtyTextures() { - _currentState.Dirty |= DirtyFlags.Textures; + SignalDirty(DirtyFlags.Textures); } public void DirtyImages() { - _currentState.Dirty |= DirtyFlags.Images; + SignalDirty(DirtyFlags.Images); } public readonly MTLRenderCommandEncoder CreateRenderCommandEncoder() @@ -161,7 +166,7 @@ namespace Ryujinx.Graphics.Metal var renderCommandEncoder = _pipeline.CommandBuffer.RenderCommandEncoder(renderPassDescriptor); // Mark all state as dirty to ensure it is set on the encoder - _currentState.Dirty |= DirtyFlags.RenderAll; + SignalDirty(DirtyFlags.RenderAll); // Cleanup renderPassDescriptor.Dispose(); @@ -175,7 +180,7 @@ namespace Ryujinx.Graphics.Metal var computeCommandEncoder = _pipeline.CommandBuffer.ComputeCommandEncoder(descriptor); // Mark all state as dirty to ensure it is set on the encoder - _currentState.Dirty |= DirtyFlags.ComputeAll; + SignalDirty(DirtyFlags.ComputeAll); // Cleanup descriptor.Dispose(); @@ -233,22 +238,22 @@ namespace Ryujinx.Graphics.Metal if ((_currentState.Dirty & DirtyFlags.Uniforms) != 0) { - UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, MetalRenderer.UniformSetIndex); + UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, Constants.ConstantBuffersSetIndex); } if ((_currentState.Dirty & DirtyFlags.Storages) != 0) { - UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, MetalRenderer.StorageSetIndex); + UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, Constants.StorageBuffersSetIndex); } if ((_currentState.Dirty & DirtyFlags.Textures) != 0) { - UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, MetalRenderer.TextureSetIndex); + UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, Constants.TexturesSetIndex); } - if (_currentState.Dirty.HasFlag(DirtyFlags.Images)) + if ((_currentState.Dirty & DirtyFlags.Images) != 0) { - UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, MetalRenderer.ImageSetIndex); + UpdateAndBind(renderCommandEncoder, _currentState.RenderProgram, Constants.ImagesSetIndex); } _currentState.Dirty &= ~DirtyFlags.RenderAll; @@ -256,29 +261,29 @@ namespace Ryujinx.Graphics.Metal public readonly void RebindComputeState(MTLComputeCommandEncoder computeCommandEncoder) { - if (_currentState.Dirty.HasFlag(DirtyFlags.ComputePipeline)) + if ((_currentState.Dirty & DirtyFlags.ComputePipeline) != 0) { SetComputePipelineState(computeCommandEncoder); } - if (_currentState.Dirty.HasFlag(DirtyFlags.Uniforms)) + if ((_currentState.Dirty & DirtyFlags.Uniforms) != 0) { - UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, MetalRenderer.UniformSetIndex); + UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, Constants.ConstantBuffersSetIndex); } - if (_currentState.Dirty.HasFlag(DirtyFlags.Storages)) + if ((_currentState.Dirty & DirtyFlags.Storages) != 0) { - UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, MetalRenderer.StorageSetIndex); + UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, Constants.StorageBuffersSetIndex); } - if (_currentState.Dirty.HasFlag(DirtyFlags.Textures)) + if ((_currentState.Dirty & DirtyFlags.Textures) != 0) { - UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, MetalRenderer.TextureSetIndex); + UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, Constants.TexturesSetIndex); } - if (_currentState.Dirty.HasFlag(DirtyFlags.Images)) + if ((_currentState.Dirty & DirtyFlags.Images) != 0) { - UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, MetalRenderer.ImageSetIndex); + UpdateAndBind(computeCommandEncoder, _currentState.ComputeProgram, Constants.ImagesSetIndex); } _currentState.Dirty &= ~DirtyFlags.ComputeAll; @@ -347,13 +352,13 @@ namespace Ryujinx.Graphics.Metal { _currentState.RenderProgram = prg; - _currentState.Dirty |= DirtyFlags.RenderPipeline | DirtyFlags.ArgBuffers; + SignalDirty(DirtyFlags.RenderPipeline | DirtyFlags.ArgBuffers); } else if (prg.ComputeFunction != IntPtr.Zero) { _currentState.ComputeProgram = prg; - _currentState.Dirty |= DirtyFlags.ComputePipeline | DirtyFlags.ArgBuffers; + SignalDirty(DirtyFlags.ComputePipeline | DirtyFlags.ArgBuffers); } } @@ -516,8 +521,7 @@ namespace Ryujinx.Graphics.Metal // Update the buffers on the pipeline UpdatePipelineVertexState(_currentState.VertexBuffers, _currentState.VertexAttribs); - // Mark dirty - _currentState.Dirty |= DirtyFlags.RenderPipeline; + SignalDirty(DirtyFlags.RenderPipeline); } public readonly void UpdateBlendDescriptors(int index, BlendDescriptor blend) @@ -541,11 +545,9 @@ namespace Ryujinx.Graphics.Metal _currentState.BlendColor = blend.BlendConstant; - // Mark dirty - _currentState.Dirty |= DirtyFlags.RenderPipeline; + SignalDirty(DirtyFlags.RenderPipeline); } - // Inlineable public void UpdateStencilState(StencilTestDescriptor stencilTest) { ref DepthStencilUid uid = ref _currentState.DepthStencilUid; @@ -574,8 +576,7 @@ namespace Ryujinx.Graphics.Metal UpdateStencilRefValue(stencilTest.FrontFuncRef, stencilTest.BackFuncRef); - // Mark dirty - _currentState.Dirty |= DirtyFlags.DepthStencil; + SignalDirty(DirtyFlags.DepthStencil); } public readonly void UpdateDepthState(DepthTestDescriptor depthTest) @@ -585,11 +586,9 @@ namespace Ryujinx.Graphics.Metal uid.DepthCompareFunction = depthTest.TestEnable ? depthTest.Func.Convert() : MTLCompareFunction.Always; uid.DepthWriteEnabled = depthTest.TestEnable && depthTest.WriteEnable; - // Mark dirty - _currentState.Dirty |= DirtyFlags.DepthStencil; + SignalDirty(DirtyFlags.DepthStencil); } - // Inlineable public readonly void UpdateDepthClamp(bool clamp) { _currentState.DepthClipMode = clamp ? MTLDepthClipMode.Clamp : MTLDepthClipMode.Clip; @@ -601,11 +600,9 @@ namespace Ryujinx.Graphics.Metal return; } - // Mark dirty - _currentState.Dirty |= DirtyFlags.DepthClamp; + SignalDirty(DirtyFlags.DepthClamp); } - // Inlineable public readonly void UpdateDepthBias(float depthBias, float slopeScale, float clamp) { _currentState.DepthBias = depthBias; @@ -619,11 +616,9 @@ namespace Ryujinx.Graphics.Metal return; } - // Mark dirty - _currentState.Dirty |= DirtyFlags.DepthBias; + SignalDirty(DirtyFlags.DepthBias); } - // Inlineable public void UpdateScissors(ReadOnlySpan> regions) { for (int i = 0; i < regions.Length; i++) @@ -646,11 +641,9 @@ namespace Ryujinx.Graphics.Metal return; } - // Mark dirty - _currentState.Dirty |= DirtyFlags.Scissors; + SignalDirty(DirtyFlags.Scissors); } - // Inlineable public void UpdateViewports(ReadOnlySpan viewports) { static float Clamp(float value) @@ -680,8 +673,7 @@ namespace Ryujinx.Graphics.Metal return; } - // Mark dirty - _currentState.Dirty |= DirtyFlags.Viewports; + SignalDirty(DirtyFlags.Viewports); } public readonly void UpdateVertexBuffers(ReadOnlySpan vertexBuffers) @@ -708,8 +700,7 @@ namespace Ryujinx.Graphics.Metal // Update the buffers on the pipeline UpdatePipelineVertexState(_currentState.VertexBuffers, _currentState.VertexAttribs); - // Mark dirty - _currentState.Dirty |= DirtyFlags.RenderPipeline; + SignalDirty(DirtyFlags.RenderPipeline); } public readonly void UpdateUniformBuffers(ReadOnlySpan buffers) @@ -726,7 +717,7 @@ namespace Ryujinx.Graphics.Metal _currentState.UniformBufferRefs[index] = new BufferRef(mtlBuffer, ref buffer); } - _currentState.Dirty |= DirtyFlags.Uniforms; + SignalDirty(DirtyFlags.Uniforms); } public readonly void UpdateStorageBuffers(ReadOnlySpan buffers) @@ -743,7 +734,7 @@ namespace Ryujinx.Graphics.Metal _currentState.StorageBufferRefs[index] = new BufferRef(mtlBuffer, ref buffer); } - _currentState.Dirty |= DirtyFlags.Storages; + SignalDirty(DirtyFlags.Storages); } public readonly void UpdateStorageBuffers(int first, ReadOnlySpan> buffers) @@ -756,10 +747,9 @@ namespace Ryujinx.Graphics.Metal _currentState.StorageBufferRefs[index] = new BufferRef(mtlBuffer); } - _currentState.Dirty |= DirtyFlags.Storages; + SignalDirty(DirtyFlags.Storages); } - // Inlineable public void UpdateCullMode(bool enable, Face face) { var dirtyScissor = (face == Face.FrontAndBack) != _currentState.CullBoth; @@ -776,15 +766,14 @@ namespace Ryujinx.Graphics.Metal } // Mark dirty - _currentState.Dirty |= DirtyFlags.CullMode; + SignalDirty(DirtyFlags.CullMode); if (dirtyScissor) { - _currentState.Dirty |= DirtyFlags.Scissors; + SignalDirty(DirtyFlags.Scissors); } } - // Inlineable public readonly void UpdateFrontFace(FrontFace frontFace) { _currentState.Winding = frontFace.Convert(); @@ -796,8 +785,7 @@ namespace Ryujinx.Graphics.Metal return; } - // Mark dirty - _currentState.Dirty |= DirtyFlags.FrontFace; + SignalDirty(DirtyFlags.FrontFace); } private readonly void UpdateStencilRefValue(int frontRef, int backRef) @@ -811,8 +799,7 @@ namespace Ryujinx.Graphics.Metal SetStencilRefValue(renderCommandEncoder); } - // Mark dirty - _currentState.Dirty |= DirtyFlags.StencilRef; + SignalDirty(DirtyFlags.StencilRef); } public readonly void UpdateTextureAndSampler(ShaderStage stage, ulong binding, TextureBase texture, Sampler sampler) @@ -826,7 +813,7 @@ namespace Ryujinx.Graphics.Metal _currentState.TextureRefs[binding] = default; } - _currentState.Dirty |= DirtyFlags.Textures; + SignalDirty(DirtyFlags.Textures); } public readonly void UpdateImage(ShaderStage stage, ulong binding, TextureBase texture) @@ -840,7 +827,7 @@ namespace Ryujinx.Graphics.Metal _currentState.ImageRefs[binding] = default; } - _currentState.Dirty |= DirtyFlags.Images; + SignalDirty(DirtyFlags.Images); } public void UpdateTextureArray(ShaderStage stage, ulong binding, TextureArray array) @@ -851,19 +838,19 @@ namespace Ryujinx.Graphics.Metal { arrayRef = new EncoderState.ArrayRef(stage, array); - _currentState.Dirty |= DirtyFlags.Textures; + SignalDirty(DirtyFlags.Textures); } } public void UpdateTextureArraySeparate(ShaderStage stage, int setIndex, TextureArray array) { - ref EncoderState.ArrayRef arrayRef = ref GetArrayRef(ref _currentState.TextureArrayRefs, setIndex); + 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); - _currentState.Dirty |= DirtyFlags.Textures; + SignalDirty(DirtyFlags.Textures); } } @@ -875,19 +862,19 @@ namespace Ryujinx.Graphics.Metal { arrayRef = new EncoderState.ArrayRef(stage, array); - _currentState.Dirty |= DirtyFlags.Images; + SignalDirty(DirtyFlags.Images); } } public void UpdateImageArraySeparate(ShaderStage stage, int setIndex, ImageArray array) { - ref EncoderState.ArrayRef arrayRef = ref GetArrayRef(ref _currentState.ImageArrayExtraRefs, setIndex); + 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); - _currentState.Dirty |= DirtyFlags.Images; + SignalDirty(DirtyFlags.Images); } } @@ -1054,7 +1041,7 @@ namespace Ryujinx.Graphics.Metal renderCommandEncoder.SetVertexBuffer(zeroMtlBuffer, 0, Constants.ZeroBufferIndex); } - private readonly void UpdateAndBind(MTLRenderCommandEncoder renderCommandEncoder, Program program, int setIndex) + private readonly void UpdateAndBind(MTLRenderCommandEncoder renderCommandEncoder, Program program, uint setIndex) { var bindingSegments = program.BindingSegments[setIndex]; @@ -1089,7 +1076,7 @@ namespace Ryujinx.Graphics.Metal switch (setIndex) { - case MetalRenderer.UniformSetIndex: + case Constants.ConstantBuffersSetIndex: for (int i = 0; i < count; i++) { int index = binding + i; @@ -1139,7 +1126,7 @@ namespace Ryujinx.Graphics.Metal renderCommandEncoder.UseResource(new MTLResource(mtlBuffer.NativePtr), MTLResourceUsage.Read, renderStages); } break; - case MetalRenderer.StorageSetIndex: + case Constants.StorageBuffersSetIndex: for (int i = 0; i < count; i++) { int index = binding + i; @@ -1170,7 +1157,7 @@ namespace Ryujinx.Graphics.Metal MTLRenderStages renderStages = 0; - if (segment.Stages.HasFlag(ResourceStages.Vertex)) + if ((segment.Stages & ResourceStages.Vertex) != 0) { vertResourceIds[vertResourceIdIndex] = mtlBuffer.GpuAddress + (ulong)offset; vertResourceIdIndex++; @@ -1178,7 +1165,7 @@ namespace Ryujinx.Graphics.Metal renderStages |= MTLRenderStages.RenderStageVertex; } - if (segment.Stages.HasFlag(ResourceStages.Fragment)) + if ((segment.Stages & ResourceStages.Fragment) != 0) { fragResourceIds[fragResourceIdIndex] = mtlBuffer.GpuAddress + (ulong)offset; fragResourceIdIndex++; @@ -1189,7 +1176,7 @@ namespace Ryujinx.Graphics.Metal renderCommandEncoder.UseResource(new MTLResource(mtlBuffer.NativePtr), MTLResourceUsage.Read, renderStages); } break; - case MetalRenderer.TextureSetIndex: + case Constants.TexturesSetIndex: if (!segment.IsArray) { for (int i = 0; i < count; i++) @@ -1247,10 +1234,106 @@ namespace Ryujinx.Graphics.Metal } else { - // TODO: Texture arrays + var textureArray = _currentState.TextureArrayRefs[binding].Array; + + if (segment.Type != ResourceType.BufferTexture) + { + var textures = textureArray.GetTextureRefs(); + var samplers = new Sampler[textures.Length]; + + for (int i = 0; i < textures.Length; i++) + { + TextureRef texture = textures[i]; + + if (texture.Storage == null) + { + continue; + } + + var mtlTexture = texture.Storage.GetHandle(); + samplers[i] = texture.Sampler; + + MTLRenderStages renderStages = 0; + + if ((segment.Stages & ResourceStages.Vertex) != 0) + { + vertResourceIds[vertResourceIdIndex] = mtlTexture.GpuResourceID._impl; + vertResourceIdIndex++; + + renderStages |= MTLRenderStages.RenderStageVertex; + } + + if ((segment.Stages & ResourceStages.Fragment) != 0) + { + fragResourceIds[fragResourceIdIndex] = mtlTexture.GpuResourceID._impl; + fragResourceIdIndex++; + + renderStages |= MTLRenderStages.RenderStageFragment; + } + + renderCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), + MTLResourceUsage.Read, renderStages); + } + + foreach (var sampler in samplers) + { + if (sampler == null) + { + continue; + } + + if ((segment.Stages & ResourceStages.Vertex) != 0) + { + vertResourceIds[vertResourceIdIndex] = sampler.GetSampler().GpuResourceID._impl; + vertResourceIdIndex++; + } + + if ((segment.Stages & ResourceStages.Fragment) != 0) + { + fragResourceIds[fragResourceIdIndex] = sampler.GetSampler().GpuResourceID._impl; + fragResourceIdIndex++; + } + } + } + else + { + var bufferTextures = textureArray.GetBufferTextureRefs(); + + foreach (TextureBuffer bufferTexture in bufferTextures) + { + if (bufferTexture == null) + { + continue; + } + + bufferTexture.RebuildStorage(false); + + var mtlTexture = bufferTexture.GetHandle(); + + MTLRenderStages renderStages = 0; + + if ((segment.Stages & ResourceStages.Vertex) != 0) + { + vertResourceIds[vertResourceIdIndex] = mtlTexture.GpuResourceID._impl; + vertResourceIdIndex++; + + renderStages |= MTLRenderStages.RenderStageVertex; + } + + if ((segment.Stages & ResourceStages.Fragment) != 0) + { + fragResourceIds[fragResourceIdIndex] = mtlTexture.GpuResourceID._impl; + fragResourceIdIndex++; + + renderStages |= MTLRenderStages.RenderStageFragment; + } + + renderCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), MTLResourceUsage.Read, renderStages); + } + } } break; - case MetalRenderer.ImageSetIndex: + case Constants.ImagesSetIndex: if (!segment.IsArray) { for (int i = 0; i < count; i++) @@ -1306,7 +1389,7 @@ namespace Ryujinx.Graphics.Metal } } - private readonly void UpdateAndBind(MTLComputeCommandEncoder computeCommandEncoder, Program program, int setIndex) + private readonly void UpdateAndBind(MTLComputeCommandEncoder computeCommandEncoder, Program program, uint setIndex) { var bindingSegments = program.BindingSegments[setIndex]; @@ -1332,7 +1415,7 @@ namespace Ryujinx.Graphics.Metal switch (setIndex) { - case MetalRenderer.UniformSetIndex: + case Constants.ConstantBuffersSetIndex: for (int i = 0; i < count; i++) { int index = binding + i; @@ -1369,7 +1452,7 @@ namespace Ryujinx.Graphics.Metal } } break; - case MetalRenderer.StorageSetIndex: + case Constants.StorageBuffersSetIndex: for (int i = 0; i < count; i++) { int index = binding + i; @@ -1406,7 +1489,7 @@ namespace Ryujinx.Graphics.Metal } } break; - case MetalRenderer.TextureSetIndex: + case Constants.TexturesSetIndex: if (!segment.IsArray) { for (int i = 0; i < count; i++) @@ -1429,7 +1512,7 @@ namespace Ryujinx.Graphics.Metal var mtlTexture = storage.GetHandle(); - if (segment.Stages.HasFlag(ResourceStages.Compute)) + if ((segment.Stages & ResourceStages.Compute) != 0) { computeCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), MTLResourceUsage.Read); resourceIds[resourceIdIndex] = mtlTexture.GpuResourceID._impl; @@ -1445,10 +1528,70 @@ namespace Ryujinx.Graphics.Metal } else { - // TODO: Texture arrays + var textureArray = _currentState.TextureArrayRefs[binding].Array; + + if (segment.Type != ResourceType.BufferTexture) + { + var textures = textureArray.GetTextureRefs(); + var samplers = new Sampler[textures.Length]; + + for (int i = 0; i < textures.Length; i++) + { + TextureRef texture = textures[i]; + + if (texture.Storage == null) + { + continue; + } + + var mtlTexture = texture.Storage.GetHandle(); + + if ((segment.Stages & ResourceStages.Compute) != 0) + { + computeCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), + MTLResourceUsage.Read); + resourceIds[resourceIdIndex] = mtlTexture.GpuResourceID._impl; + resourceIdIndex++; + + samplers[i] = texture.Sampler; + } + } + + foreach (var sampler in samplers) + { + if (sampler != null) + { + resourceIds[resourceIdIndex] = sampler.GetSampler().GpuResourceID._impl; + resourceIdIndex++; + } + } + } + else + { + var bufferTextures = textureArray.GetBufferTextureRefs(); + + foreach (TextureBuffer bufferTexture in bufferTextures) + { + if (bufferTexture == null) + { + continue; + } + + bufferTexture.RebuildStorage(false); + + var mtlTexture = bufferTexture.GetHandle(); + + if ((segment.Stages & ResourceStages.Compute) != 0) + { + computeCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), MTLResourceUsage.Read); + resourceIds[resourceIdIndex] = mtlTexture.GpuResourceID._impl; + resourceIdIndex++; + } + } + } } break; - case MetalRenderer.ImageSetIndex: + case Constants.ImagesSetIndex: if (!segment.IsArray) { if (segment.Type != ResourceType.BufferTexture) @@ -1468,7 +1611,7 @@ namespace Ryujinx.Graphics.Metal var mtlTexture = storage.GetHandle(); - if (segment.Stages.HasFlag(ResourceStages.Compute)) + if ((segment.Stages & ResourceStages.Compute) != 0) { computeCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), MTLResourceUsage.Read | MTLResourceUsage.Write); resourceIds[resourceIdIndex] = mtlTexture.GpuResourceID._impl; @@ -1489,14 +1632,14 @@ namespace Ryujinx.Graphics.Metal } } - private static uint SetIndexToBindingIndex(int setIndex) + private static uint SetIndexToBindingIndex(uint setIndex) { return setIndex switch { - MetalRenderer.UniformSetIndex => Constants.ConstantBuffersIndex, - MetalRenderer.StorageSetIndex => Constants.StorageBuffersIndex, - MetalRenderer.TextureSetIndex => Constants.TexturesIndex, - MetalRenderer.ImageSetIndex => Constants.ImagesIndex, + Constants.ConstantBuffersSetIndex => Constants.ConstantBuffersIndex, + Constants.StorageBuffersSetIndex => Constants.StorageBuffersIndex, + Constants.TexturesSetIndex => Constants.TexturesIndex, + Constants.ImagesSetIndex => Constants.ImagesIndex, }; } diff --git a/src/Ryujinx.Graphics.Metal/HelperShader.cs b/src/Ryujinx.Graphics.Metal/HelperShader.cs index ed9a7f656..7e20ec221 100644 --- a/src/Ryujinx.Graphics.Metal/HelperShader.cs +++ b/src/Ryujinx.Graphics.Metal/HelperShader.cs @@ -123,7 +123,16 @@ namespace Ryujinx.Graphics.Metal private static string ReadMsl(string fileName) { - return EmbeddedResources.ReadAllText(string.Join('/', ShadersSourcePath, fileName)); + var 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( diff --git a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs index cd2a83bff..35e721e94 100644 --- a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs +++ b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs @@ -13,11 +13,6 @@ namespace Ryujinx.Graphics.Metal { public const int TotalSets = 4; - public const int UniformSetIndex = 0; - public const int StorageSetIndex = 1; - public const int TextureSetIndex = 2; - public const int ImageSetIndex = 3; - private readonly MTLDevice _device; private readonly MTLCommandQueue _queue; private readonly Func _getMetalLayer; @@ -181,8 +176,7 @@ namespace Ryujinx.Graphics.Metal supportsCubemapView: true, supportsNonConstantTextureOffset: false, supportsQuads: false, - // TODO: Metal Bindless Support - supportsSeparateSampler: false, + supportsSeparateSampler: true, supportsShaderBallot: false, supportsShaderBarrierDivergence: false, supportsShaderFloat64: false, @@ -194,12 +188,12 @@ namespace Ryujinx.Graphics.Metal supportsViewportSwizzle: false, supportsIndirectParameters: true, supportsDepthClipControl: false, - uniformBufferSetIndex: UniformSetIndex, - storageBufferSetIndex: StorageSetIndex, - textureSetIndex: TextureSetIndex, - imageSetIndex: ImageSetIndex, - extraSetBaseIndex: 0, - maximumExtraSets: 0, + 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, diff --git a/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs b/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs index e969ce82b..36ae9bac6 100644 --- a/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs +++ b/src/Ryujinx.Graphics.Metal/ResourceLayoutBuilder.cs @@ -27,12 +27,12 @@ namespace Ryujinx.Graphics.Metal public ResourceLayoutBuilder Add(ResourceStages stages, ResourceType type, int binding, bool write = false) { - int setIndex = type switch + uint setIndex = type switch { - ResourceType.UniformBuffer => MetalRenderer.UniformSetIndex, - ResourceType.StorageBuffer => MetalRenderer.StorageSetIndex, - ResourceType.TextureAndSampler or ResourceType.BufferTexture => MetalRenderer.TextureSetIndex, - ResourceType.Image or ResourceType.BufferImage => MetalRenderer.ImageSetIndex, + 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}\"."), }; diff --git a/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal b/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal index a5e4e8170..7caf0c846 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/Blit.metal @@ -22,7 +22,7 @@ struct Textures }; vertex CopyVertexOut vertexMain(uint vid [[vertex_id]], - constant ConstantBuffers &constant_buffers [[buffer(20)]]) { + constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) { CopyVertexOut out; int low = vid & 1; @@ -38,6 +38,6 @@ vertex CopyVertexOut vertexMain(uint vid [[vertex_id]], } fragment float4 fragmentMain(CopyVertexOut in [[stage_in]], - constant Textures &textures [[buffer(22)]]) { + 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 index 09c5d76ca..86ee306d3 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal @@ -13,7 +13,7 @@ struct Textures }; fragment float4 fragmentMain(CopyVertexOut in [[stage_in]], - constant Textures &textures [[buffer(22)]], + 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)); diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal b/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal index 492a27d21..4424ac531 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal @@ -23,8 +23,8 @@ struct StorageBuffers { device OutData* out_data; }; -kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(20)]], - device StorageBuffers &storage_buffers [[buffer(21)]], +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 [[threads_per_grid]]) diff --git a/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal b/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal index d3ef9603f..306fad87a 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal @@ -33,6 +33,6 @@ struct FragmentOut { }; fragment FragmentOut fragmentMain(VertexOut in [[stage_in]], - constant ConstantBuffers &constant_buffers [[buffer(20)]]) { + constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) { return {constant_buffers.clear_color->data}; } diff --git a/src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal b/src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal index c6b547be8..8b8467c2f 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal @@ -18,7 +18,7 @@ struct FragmentOut { }; fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]], - constant Textures &textures [[buffer(22)]]) { + constant Textures &textures [[buffer(TEXTURES_INDEX)]]) { FragmentOut out; out.depth = textures.texture.sample(textures.sampler, in.uv).r; diff --git a/src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal b/src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal index 9fb5e6e50..10791f636 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal @@ -17,7 +17,7 @@ struct FragmentOut { }; fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]], - constant Textures &textures [[buffer(22)]], + constant Textures &textures [[buffer(TEXTURES_INDEX)]], uint sample_id [[sample_id]]) { FragmentOut out; diff --git a/src/Ryujinx.Graphics.Metal/Shaders/DepthStencilClear.metal b/src/Ryujinx.Graphics.Metal/Shaders/DepthStencilClear.metal index 4ee4f4a51..7e50f2ce7 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/DepthStencilClear.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/DepthStencilClear.metal @@ -33,7 +33,7 @@ vertex VertexOut vertexMain(ushort vid [[vertex_id]]) { } fragment FragmentOut fragmentMain(VertexOut in [[stage_in]], - constant ConstantBuffers &constant_buffers [[buffer(20)]]) { + constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) { FragmentOut out; out.depth = constant_buffers.clear_depth->data; diff --git a/src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal b/src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal index da7c6e90a..0b25f322d 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal @@ -18,7 +18,7 @@ struct FragmentOut { }; fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]], - constant Textures &textures [[buffer(22)]]) { + constant Textures &textures [[buffer(TEXTURES_INDEX)]]) { FragmentOut out; out.stencil = textures.texture.sample(textures.sampler, in.uv).r; diff --git a/src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal b/src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal index 3948eacc7..e7f2d20b7 100644 --- a/src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal +++ b/src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal @@ -17,7 +17,7 @@ struct FragmentOut { }; fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]], - constant Textures &textures [[buffer(22)]], + constant Textures &textures [[buffer(TEXTURES_INDEX)]], uint sample_id [[sample_id]]) { FragmentOut out; diff --git a/src/Ryujinx.Graphics.Metal/TextureArray.cs b/src/Ryujinx.Graphics.Metal/TextureArray.cs index 762e6a5fd..cfca843f7 100644 --- a/src/Ryujinx.Graphics.Metal/TextureArray.cs +++ b/src/Ryujinx.Graphics.Metal/TextureArray.cs @@ -73,6 +73,16 @@ namespace Ryujinx.Graphics.Metal SetDirty(); } + public TextureRef[] GetTextureRefs() + { + return _textureRefs; + } + + public TextureBuffer[] GetBufferTextureRefs() + { + return _bufferTextureRefs; + } + private void SetDirty() { _pipeline.DirtyTextures(); diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs index e31e397c1..e05c30282 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs @@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl * */ - public static void Declare(CodeGenContext context, StructuredProgramInfo info) + public static int[] Declare(CodeGenContext context, StructuredProgramInfo info) { // TODO: Re-enable this warning context.AppendLine("#pragma clang diagnostic ignored \"-Wunused-variable\""); @@ -75,10 +75,32 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl context.AppendLine(); DeclareOutputAttributes(context, info.IoDefinitions.Where(x => x.StorageKind == StorageKind.Output)); context.AppendLine(); - DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values, true, fsi); - DeclareBufferStructures(context, context.Properties.StorageBuffers.Values, false, fsi); - DeclareTextures(context, context.Properties.Textures.Values); - DeclareImages(context, context.Properties.Images.Values, fsi); + DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values.OrderBy(x => x.Binding).ToArray(), true, fsi); + DeclareBufferStructures(context, context.Properties.StorageBuffers.Values.OrderBy(x => x.Binding).ToArray(), false, fsi); + + // We need to declare each set as a new struct + var textureDefinitions = context.Properties.Textures.Values + .GroupBy(x => x.Set) + .ToDictionary(x => x.Key, x => x.OrderBy(y => y.Binding).ToArray()); + + var imageDefinitions = context.Properties.Images.Values + .GroupBy(x => x.Set) + .ToDictionary(x => x.Key, x => x.OrderBy(y => y.Binding).ToArray()); + + var textureSets = textureDefinitions.Keys.ToArray(); + var imageSets = imageDefinitions.Keys.ToArray(); + + var sets = textureSets.Union(imageSets).ToArray(); + + foreach (var set in textureDefinitions) + { + DeclareTextures(context, set.Value, set.Key); + } + + foreach (var set in imageDefinitions) + { + DeclareImages(context, set.Value, set.Key, fsi); + } if ((info.HelperFunctionsMask & HelperFunctionsMask.FindLSB) != 0) { @@ -99,6 +121,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl { AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Msl/HelperFunctions/SwizzleAdd.metal"); } + + return sets; } static bool IsUserDefined(IoDefinition ioDefinition, StorageKind storageKind) @@ -186,22 +210,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl } } - private static void DeclareBufferStructures(CodeGenContext context, IEnumerable buffers, bool constant, bool fsi) + private static void DeclareBufferStructures(CodeGenContext context, BufferDefinition[] buffers, bool constant, bool fsi) { var name = constant ? "ConstantBuffers" : "StorageBuffers"; var addressSpace = constant ? "constant" : "device"; - List argBufferPointers = []; + string[] bufferDec = new string[buffers.Length]; - // TODO: Avoid Linq if we can - var sortedBuffers = buffers.OrderBy(x => x.Binding).ToArray(); - - foreach (BufferDefinition buffer in sortedBuffers) + for (int i = 0; i < buffers.Length; i++) { + BufferDefinition buffer = buffers[i]; + var needsPadding = buffer.Layout == BufferLayout.Std140; string fsiSuffix = constant && fsi ? " [[raster_order_group(0)]]" : ""; - argBufferPointers.Add($"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name}{fsiSuffix};"); + bufferDec[i] = $"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name}{fsiSuffix};"; context.AppendLine($"struct {Defaults.StructPrefix}_{buffer.Name}"); context.EnterScope(); @@ -209,7 +232,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl foreach (StructureField field in buffer.Type.Fields) { var type = field.Type; - type |= (needsPadding && (field.Type & AggregateType.Array) != 0) ? AggregateType.Vector4 : AggregateType.Invalid; + type |= (needsPadding && (field.Type & AggregateType.Array) != 0) + ? AggregateType.Vector4 + : AggregateType.Invalid; type &= ~AggregateType.Array; @@ -239,66 +264,85 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl context.AppendLine($"struct {name}"); context.EnterScope(); - foreach (var pointer in argBufferPointers) + foreach (var declaration in bufferDec) { - context.AppendLine(pointer); + context.AppendLine(declaration); } context.LeaveScope(";"); context.AppendLine(); } - private static void DeclareTextures(CodeGenContext context, IEnumerable textures) + private static void DeclareTextures(CodeGenContext context, TextureDefinition[] textures, int set) { - context.AppendLine("struct Textures"); + var setName = GetNameForSet(set); + context.AppendLine($"struct {setName}"); context.EnterScope(); - List argBufferPointers = []; + List textureDec = []; - // TODO: Avoid Linq if we can - var sortedTextures = textures.OrderBy(x => x.Binding).ToArray(); - - foreach (TextureDefinition texture in sortedTextures) + foreach (TextureDefinition texture in textures) { - var textureTypeName = texture.Type.ToMslTextureType(); - argBufferPointers.Add($"{textureTypeName} tex_{texture.Name};"); + if (texture.Type != SamplerType.None) + { + var textureTypeName = texture.Type.ToMslTextureType(); + + if (texture.ArrayLength > 1) + { + textureTypeName = $"array<{textureTypeName}, {texture.ArrayLength}>"; + } + + textureDec.Add($"{textureTypeName} tex_{texture.Name};"); + } if (!texture.Separate && texture.Type != SamplerType.TextureBuffer) { - argBufferPointers.Add($"sampler samp_{texture.Name};"); + var samplerType = "sampler"; + + if (texture.ArrayLength > 1) + { + samplerType = $"array<{samplerType}, {texture.ArrayLength}>"; + } + + textureDec.Add($"{samplerType} samp_{texture.Name};"); } } - foreach (var pointer in argBufferPointers) + foreach (var declaration in textureDec) { - context.AppendLine(pointer); + context.AppendLine(declaration); } context.LeaveScope(";"); context.AppendLine(); } - private static void DeclareImages(CodeGenContext context, IEnumerable images, bool fsi) + private static void DeclareImages(CodeGenContext context, TextureDefinition[] images, int set, bool fsi) { - context.AppendLine("struct Images"); + var setName = GetNameForSet(set); + context.AppendLine($"struct {setName}"); context.EnterScope(); - List argBufferPointers = []; + string[] imageDec = new string[images.Length]; - // TODO: Avoid Linq if we can - var sortedImages = images.OrderBy(x => x.Binding).ToArray(); - - foreach (TextureDefinition image in sortedImages) + for (int i = 0; i < images.Length; i++) { + TextureDefinition image = images[i]; + var imageTypeName = image.Type.ToMslTextureType(true); + if (image.ArrayLength > 1) + { + imageTypeName = $"array<{imageTypeName}, {image.ArrayLength}>"; + } + string fsiSuffix = fsi ? " [[raster_order_group(0)]]" : ""; - argBufferPointers.Add($"{imageTypeName} {image.Name}{fsiSuffix};"); + imageDec[i] = $"{imageTypeName} {image.Name}{fsiSuffix};"; } - foreach (var pointer in argBufferPointers) + foreach (var declaration in imageDec) { - context.AppendLine(pointer); + context.AppendLine(declaration); } context.LeaveScope(";"); @@ -483,5 +527,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl context.AppendLine(code); context.AppendLine(); } + + public static string GetNameForSet(int set, bool forVar = false) + { + return (uint)set switch + { + Defaults.TexturesSetIndex => forVar ? "textures" : "Textures", + Defaults.ImagesSetIndex => forVar ? "images" : "Images", + _ => $"{(forVar ? "set" : "Set")}{set}" + }; + } } } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Defaults.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Defaults.cs index a78de36ce..511a2f606 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Defaults.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Defaults.cs @@ -14,14 +14,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl public const string UndefinedName = "0"; - public const int MaxUniformBuffersPerStage = 18; - public const int MaxStorageBuffersPerStage = 16; - public const int MaxTexturesPerStage = 64; + public const int MaxVertexBuffers = 16; - public const uint ConstantBuffersIndex = 20; - public const uint StorageBuffersIndex = 21; - public const uint TexturesIndex = 22; - public const uint ImagesIndex = 23; + 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 int TotalClipDistances = 8; } diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Instructions/InstGenMemory.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Instructions/InstGenMemory.cs index 198d0cf8d..f6fa7aa73 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Instructions/InstGenMemory.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Instructions/InstGenMemory.cs @@ -494,13 +494,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions { TextureDefinition textureDefinition = context.Properties.Textures[texOp.GetTextureSetAndBinding()]; string name = textureDefinition.Name; + string setName = Declarations.GetNameForSet(textureDefinition.Set, true); if (textureDefinition.ArrayLength != 1) { name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; } - return $"textures.tex_{name}"; + return $"{setName}.tex_{name}"; } private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex) @@ -510,26 +511,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions TextureDefinition samplerDefinition = context.Properties.Textures[index]; string name = samplerDefinition.Name; + string setName = Declarations.GetNameForSet(samplerDefinition.Set, true); if (samplerDefinition.ArrayLength != 1) { name = $"{name}[{GetSourceExpr(context, texOp.GetSource(sourceIndex), AggregateType.S32)}]"; } - return $"textures.samp_{name}"; + return $"{setName}.samp_{name}"; } private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex) { - TextureDefinition definition = context.Properties.Images[texOp.GetTextureSetAndBinding()]; - string name = definition.Name; + TextureDefinition imageDefinition = context.Properties.Images[texOp.GetTextureSetAndBinding()]; + string name = imageDefinition.Name; + string setName = Declarations.GetNameForSet(imageDefinition.Set, true); - if (definition.ArrayLength != 1) + if (imageDefinition.ArrayLength != 1) { name = $"{name}[{GetSourceExpr(context, texOp.GetSource(srcIndex++), AggregateType.S32)}]"; } - return $"images.{name}"; + return $"{setName}.{name}"; } private static string GetMaskMultiDest(int mask) diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/MslGenerator.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/MslGenerator.cs index 28a69c508..7de6ee5dd 100644 --- a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/MslGenerator.cs +++ b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/MslGenerator.cs @@ -20,28 +20,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl CodeGenContext context = new(info, parameters); - Declarations.Declare(context, info); + var sets = Declarations.Declare(context, info); if (info.Functions.Count != 0) { for (int i = 1; i < info.Functions.Count; i++) { - PrintFunction(context, info.Functions[i], parameters.Definitions.Stage); + PrintFunction(context, info.Functions[i], parameters.Definitions.Stage, sets); context.AppendLine(); } } - PrintFunction(context, info.Functions[0], parameters.Definitions.Stage, true); + PrintFunction(context, info.Functions[0], parameters.Definitions.Stage, sets, true); return context.GetCode(); } - private static void PrintFunction(CodeGenContext context, StructuredFunction function, ShaderStage stage, bool isMainFunc = false) + private static void PrintFunction(CodeGenContext context, StructuredFunction function, ShaderStage stage, int[] sets, bool isMainFunc = false) { context.CurrentFunction = function; - context.AppendLine(GetFunctionSignature(context, function, stage, isMainFunc)); + context.AppendLine(GetFunctionSignature(context, function, stage, sets, isMainFunc)); context.EnterScope(); Declarations.DeclareLocals(context, function, stage, isMainFunc); @@ -61,6 +61,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl CodeGenContext context, StructuredFunction function, ShaderStage stage, + int[] sets, bool isMainFunc = false) { int additionalArgCount = isMainFunc ? 0 : CodeGenContext.AdditionalArgCount + (context.Definitions.Stage != ShaderStage.Compute ? 1 : 0); @@ -166,8 +167,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl args = args.Append($"constant ConstantBuffers &constant_buffers [[buffer({Defaults.ConstantBuffersIndex})]]").ToArray(); args = args.Append($"device StorageBuffers &storage_buffers [[buffer({Defaults.StorageBuffersIndex})]]").ToArray(); - args = args.Append($"constant Textures &textures [[buffer({Defaults.TexturesIndex})]]").ToArray(); - args = args.Append($"constant Images &images [[buffer({Defaults.ImagesIndex})]]").ToArray(); + + foreach (var set in sets) + { + var bindingIndex = set + Defaults.BaseSetIndex; + args = args.Append($"constant {Declarations.GetNameForSet(set)} &{Declarations.GetNameForSet(set, true)} [[buffer({bindingIndex})]]").ToArray(); + } } var funcPrefix = $"{funcKeyword} {returnType} {funcName ?? function.Name}("; diff --git a/src/Ryujinx.Graphics.Shader/SamplerType.cs b/src/Ryujinx.Graphics.Shader/SamplerType.cs index 44ff13294..49c5222e4 100644 --- a/src/Ryujinx.Graphics.Shader/SamplerType.cs +++ b/src/Ryujinx.Graphics.Shader/SamplerType.cs @@ -192,7 +192,7 @@ namespace Ryujinx.Graphics.Shader typeName += "_array"; } - return $"{typeName} "; + return $"{typeName}"; } } }