Shader Extra Set Support + Cleanup (#36)
Separate samplers are now supported and arrays in constant sets are bound
This commit is contained in:
parent
d9025904a7
commit
4cd15cb1a6
20 changed files with 412 additions and 181 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Rectangle<int>> 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<Viewport> 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<VertexBufferDescriptor> 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<BufferAssignment> 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<BufferAssignment> 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<Auto<DisposableBuffer>> 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<TextureArray>(stage, array);
|
||||
|
||||
_currentState.Dirty |= DirtyFlags.Textures;
|
||||
SignalDirty(DirtyFlags.Textures);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTextureArraySeparate(ShaderStage stage, int setIndex, TextureArray array)
|
||||
{
|
||||
ref EncoderState.ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _currentState.TextureArrayRefs, setIndex);
|
||||
ref EncoderState.ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _currentState.TextureArrayExtraRefs, setIndex - MetalRenderer.TotalSets);
|
||||
|
||||
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||
{
|
||||
arrayRef = new EncoderState.ArrayRef<TextureArray>(stage, array);
|
||||
|
||||
_currentState.Dirty |= DirtyFlags.Textures;
|
||||
SignalDirty(DirtyFlags.Textures);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -875,19 +862,19 @@ namespace Ryujinx.Graphics.Metal
|
|||
{
|
||||
arrayRef = new EncoderState.ArrayRef<ImageArray>(stage, array);
|
||||
|
||||
_currentState.Dirty |= DirtyFlags.Images;
|
||||
SignalDirty(DirtyFlags.Images);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateImageArraySeparate(ShaderStage stage, int setIndex, ImageArray array)
|
||||
{
|
||||
ref EncoderState.ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _currentState.ImageArrayExtraRefs, setIndex);
|
||||
ref EncoderState.ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _currentState.ImageArrayExtraRefs, setIndex - MetalRenderer.TotalSets);
|
||||
|
||||
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||
{
|
||||
arrayRef = new EncoderState.ArrayRef<ImageArray>(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,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<CAMetalLayer> _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,
|
||||
|
|
|
@ -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}\"."),
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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]])
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -73,6 +73,16 @@ namespace Ryujinx.Graphics.Metal
|
|||
SetDirty();
|
||||
}
|
||||
|
||||
public TextureRef[] GetTextureRefs()
|
||||
{
|
||||
return _textureRefs;
|
||||
}
|
||||
|
||||
public TextureBuffer[] GetBufferTextureRefs()
|
||||
{
|
||||
return _bufferTextureRefs;
|
||||
}
|
||||
|
||||
private void SetDirty()
|
||||
{
|
||||
_pipeline.DirtyTextures();
|
||||
|
|
|
@ -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<BufferDefinition> 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<string> 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<TextureDefinition> 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<string> argBufferPointers = [];
|
||||
List<string> 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<TextureDefinition> 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<string> 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}"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}(";
|
||||
|
|
|
@ -192,7 +192,7 @@ namespace Ryujinx.Graphics.Shader
|
|||
typeName += "_array";
|
||||
}
|
||||
|
||||
return $"{typeName} <float{(image ? ", access::read_write" : "")}>";
|
||||
return $"{typeName}<float{(image ? ", access::read_write" : "")}>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue