mirror of
https://github.com/GreemDev/Ryujinx
synced 2024-12-13 03:29:56 +01:00
Argument Buffers (#24)
* Stuff * More arg buffer stuff * Fixes * Rebase * Pass storage buffers to inline functions * Fix binding * Fix typo + Fix a couple shaders * Enforce ids * Dispose * Mark used buffers as resident * Update depth clear shader * Fix non-contiguous struct defs * Update ChangeBufferStride * Fix StorageBuffer assignments * Fix odyssey crash * Retain buffer bindings * Pad Std140 * Set texture data with safe buffers * Clone buffers * Always declare vert in * Stop clears from breaking OpenGL games * Fix depth clear * Use invariant position * Horribly inefficient texture & sampler arg buffers * Fix missing struct access * Minimise rebinds as much as possible * Build arg buffers on staging buffer
This commit is contained in:
parent
a71b5f1a3a
commit
c8308d27f1
20 changed files with 721 additions and 402 deletions
|
@ -4,19 +4,23 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
// TODO: Check these values, these were largely copied from Vulkan
|
// TODO: Check these values, these were largely copied from Vulkan
|
||||||
public const int MaxShaderStages = 5;
|
public const int MaxShaderStages = 5;
|
||||||
|
public const int MaxVertexBuffers = 16;
|
||||||
public const int MaxUniformBuffersPerStage = 18;
|
public const int MaxUniformBuffersPerStage = 18;
|
||||||
public const int MaxStorageBuffersPerStage = 16;
|
public const int MaxStorageBuffersPerStage = 16;
|
||||||
public const int MaxTexturesPerStage = 64;
|
public const int MaxTexturesPerStage = 64;
|
||||||
public const int MaxCommandBuffersPerQueue = 16;
|
|
||||||
public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages;
|
public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages;
|
||||||
public const int MaxColorAttachments = 8;
|
public const int MaxColorAttachments = 8;
|
||||||
// TODO: Check this value
|
// TODO: Check this value
|
||||||
public const int MaxVertexAttributes = 31;
|
public const int MaxVertexAttributes = 31;
|
||||||
// TODO: Check this value
|
// TODO: Check this value
|
||||||
public const int MaxVertexLayouts = 31;
|
public const int MaxVertexLayouts = 31;
|
||||||
public const int MaxTextures = 31;
|
|
||||||
public const int MaxSamplers = 16;
|
|
||||||
|
|
||||||
public const int MinResourceAlignment = 16;
|
public const int MinResourceAlignment = 16;
|
||||||
|
|
||||||
|
// Must match constants set in shader generation
|
||||||
|
public const uint ConstantBuffersIndex = 20;
|
||||||
|
public const uint StorageBuffersIndex = 21;
|
||||||
|
public const uint ZeroBufferIndex = 18;
|
||||||
|
public const uint TexturesIndex = 22;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,49 @@
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using SharpMetal.Metal;
|
using SharpMetal.Metal;
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
struct DirtyFlags
|
[Flags]
|
||||||
|
enum DirtyFlags
|
||||||
{
|
{
|
||||||
public bool RenderPipeline = false;
|
None = 0,
|
||||||
public bool ComputePipeline = false;
|
RenderPipeline = 1 << 0,
|
||||||
public bool DepthStencil = false;
|
ComputePipeline = 1 << 1,
|
||||||
|
DepthStencil = 1 << 2,
|
||||||
|
DepthClamp = 1 << 3,
|
||||||
|
DepthBias = 1 << 4,
|
||||||
|
CullMode = 1 << 5,
|
||||||
|
FrontFace = 1 << 6,
|
||||||
|
StencilRef = 1 << 7,
|
||||||
|
Viewports = 1 << 8,
|
||||||
|
Scissors = 1 << 9,
|
||||||
|
VertexBuffers = 1 << 10,
|
||||||
|
Buffers = 1 << 11,
|
||||||
|
VertexTextures = 1 << 12,
|
||||||
|
FragmentTextures = 1 << 13,
|
||||||
|
ComputeTextures = 1 << 14,
|
||||||
|
|
||||||
public DirtyFlags() { }
|
RenderAll = RenderPipeline | DepthStencil | DepthClamp | DepthBias | CullMode | FrontFace | StencilRef | Viewports | Scissors | VertexBuffers | Buffers | VertexTextures | FragmentTextures,
|
||||||
|
ComputeAll = ComputePipeline | Buffers | ComputeTextures,
|
||||||
public void MarkAll()
|
All = RenderAll | ComputeAll,
|
||||||
{
|
|
||||||
RenderPipeline = true;
|
|
||||||
ComputePipeline = true;
|
|
||||||
DepthStencil = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
record struct BufferRef
|
record struct BufferRef
|
||||||
{
|
{
|
||||||
public Auto<DisposableBuffer> Buffer;
|
public Auto<DisposableBuffer> Buffer;
|
||||||
public int Index;
|
|
||||||
public BufferRange? Range;
|
public BufferRange? Range;
|
||||||
|
|
||||||
public BufferRef(Auto<DisposableBuffer> buffer, int index)
|
public BufferRef(Auto<DisposableBuffer> buffer)
|
||||||
{
|
{
|
||||||
Buffer = buffer;
|
Buffer = buffer;
|
||||||
Index = index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferRef(Auto<DisposableBuffer> buffer, int index, ref BufferRange range)
|
public BufferRef(Auto<DisposableBuffer> buffer, ref BufferRange range)
|
||||||
{
|
{
|
||||||
Buffer = buffer;
|
Buffer = buffer;
|
||||||
Index = index;
|
|
||||||
Range = range;
|
Range = range;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,17 +55,17 @@ namespace Ryujinx.Graphics.Metal
|
||||||
public MTLFunction? FragmentFunction = null;
|
public MTLFunction? FragmentFunction = null;
|
||||||
public MTLFunction? ComputeFunction = null;
|
public MTLFunction? ComputeFunction = null;
|
||||||
|
|
||||||
public TextureBase[] FragmentTextures = new TextureBase[Constants.MaxTextures];
|
public TextureBase[] FragmentTextures = new TextureBase[Constants.MaxTexturesPerStage];
|
||||||
public MTLSamplerState[] FragmentSamplers = new MTLSamplerState[Constants.MaxSamplers];
|
public MTLSamplerState[] FragmentSamplers = new MTLSamplerState[Constants.MaxTexturesPerStage];
|
||||||
|
|
||||||
public TextureBase[] VertexTextures = new TextureBase[Constants.MaxTextures];
|
public TextureBase[] VertexTextures = new TextureBase[Constants.MaxTexturesPerStage];
|
||||||
public MTLSamplerState[] VertexSamplers = new MTLSamplerState[Constants.MaxSamplers];
|
public MTLSamplerState[] VertexSamplers = new MTLSamplerState[Constants.MaxTexturesPerStage];
|
||||||
|
|
||||||
public TextureBase[] ComputeTextures = new TextureBase[Constants.MaxTextures];
|
public TextureBase[] ComputeTextures = new TextureBase[Constants.MaxTexturesPerStage];
|
||||||
public MTLSamplerState[] ComputeSamplers = new MTLSamplerState[Constants.MaxSamplers];
|
public MTLSamplerState[] ComputeSamplers = new MTLSamplerState[Constants.MaxTexturesPerStage];
|
||||||
|
|
||||||
public BufferRef[] UniformBuffers = [];
|
public BufferRef[] UniformBuffers = new BufferRef[Constants.MaxUniformBuffersPerStage];
|
||||||
public BufferRef[] StorageBuffers = [];
|
public BufferRef[] StorageBuffers = new BufferRef[Constants.MaxStorageBuffersPerStage];
|
||||||
|
|
||||||
public Auto<DisposableBuffer> IndexBuffer = default;
|
public Auto<DisposableBuffer> IndexBuffer = default;
|
||||||
public MTLIndexType IndexType = MTLIndexType.UInt16;
|
public MTLIndexType IndexType = MTLIndexType.UInt16;
|
||||||
|
@ -99,7 +106,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
public VertexAttribDescriptor[] VertexAttribs = [];
|
public VertexAttribDescriptor[] VertexAttribs = [];
|
||||||
|
|
||||||
// Dirty flags
|
// Dirty flags
|
||||||
public DirtyFlags Dirty = new();
|
public DirtyFlags Dirty = DirtyFlags.None;
|
||||||
|
|
||||||
// Only to be used for present
|
// Only to be used for present
|
||||||
public bool ClearLoadAction = false;
|
public bool ClearLoadAction = false;
|
||||||
|
@ -119,6 +126,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
clone.BlendDescriptors = (BlendDescriptor?[])BlendDescriptors.Clone();
|
clone.BlendDescriptors = (BlendDescriptor?[])BlendDescriptors.Clone();
|
||||||
clone.VertexBuffers = (VertexBufferDescriptor[])VertexBuffers.Clone();
|
clone.VertexBuffers = (VertexBufferDescriptor[])VertexBuffers.Clone();
|
||||||
clone.VertexAttribs = (VertexAttribDescriptor[])VertexAttribs.Clone();
|
clone.VertexAttribs = (VertexAttribDescriptor[])VertexAttribs.Clone();
|
||||||
|
clone.UniformBuffers = (BufferRef[])UniformBuffers.Clone();
|
||||||
|
clone.StorageBuffers = (BufferRef[])StorageBuffers.Clone();
|
||||||
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,21 +79,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
_currentState = _backStates.Pop();
|
_currentState = _backStates.Pop();
|
||||||
|
|
||||||
// Set all the inline state, since it might have changed
|
|
||||||
var renderCommandEncoder = _pipeline.GetOrCreateRenderEncoder();
|
|
||||||
SetDepthClamp(renderCommandEncoder);
|
|
||||||
SetDepthBias(renderCommandEncoder);
|
|
||||||
SetScissors(renderCommandEncoder);
|
|
||||||
SetViewports(renderCommandEncoder);
|
|
||||||
SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.UniformBuffers, true);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.StorageBuffers, true);
|
|
||||||
SetCullMode(renderCommandEncoder);
|
|
||||||
SetFrontFace(renderCommandEncoder);
|
|
||||||
SetStencilRefValue(renderCommandEncoder);
|
|
||||||
|
|
||||||
// Mark the other state as dirty
|
// Mark the other state as dirty
|
||||||
_currentState.Dirty.MarkAll();
|
_currentState.Dirty |= DirtyFlags.All;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -165,29 +152,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
var renderCommandEncoder = _pipeline.CommandBuffer.RenderCommandEncoder(renderPassDescriptor);
|
var renderCommandEncoder = _pipeline.CommandBuffer.RenderCommandEncoder(renderPassDescriptor);
|
||||||
|
|
||||||
// Mark all state as dirty to ensure it is set on the encoder
|
// Mark all state as dirty to ensure it is set on the encoder
|
||||||
_currentState.Dirty.MarkAll();
|
_currentState.Dirty |= DirtyFlags.RenderAll;
|
||||||
|
|
||||||
// Rebind all the state
|
|
||||||
SetDepthClamp(renderCommandEncoder);
|
|
||||||
SetDepthBias(renderCommandEncoder);
|
|
||||||
SetCullMode(renderCommandEncoder);
|
|
||||||
SetFrontFace(renderCommandEncoder);
|
|
||||||
SetStencilRefValue(renderCommandEncoder);
|
|
||||||
SetViewports(renderCommandEncoder);
|
|
||||||
SetScissors(renderCommandEncoder);
|
|
||||||
SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.UniformBuffers, true);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.StorageBuffers, true);
|
|
||||||
for (ulong i = 0; i < Constants.MaxTextures; i++)
|
|
||||||
{
|
|
||||||
SetRenderTexture(renderCommandEncoder, ShaderStage.Vertex, i, _currentState.VertexTextures[i]);
|
|
||||||
SetRenderTexture(renderCommandEncoder, ShaderStage.Fragment, i, _currentState.FragmentTextures[i]);
|
|
||||||
}
|
|
||||||
for (ulong i = 0; i < Constants.MaxSamplers; i++)
|
|
||||||
{
|
|
||||||
SetRenderSampler(renderCommandEncoder, ShaderStage.Vertex, i, _currentState.VertexSamplers[i]);
|
|
||||||
SetRenderSampler(renderCommandEncoder, ShaderStage.Fragment, i, _currentState.FragmentSamplers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
renderPassDescriptor.Dispose();
|
renderPassDescriptor.Dispose();
|
||||||
|
@ -195,22 +160,13 @@ namespace Ryujinx.Graphics.Metal
|
||||||
return renderCommandEncoder;
|
return renderCommandEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly MTLComputeCommandEncoder CreateComputeCommandEncoder()
|
public MTLComputeCommandEncoder CreateComputeCommandEncoder()
|
||||||
{
|
{
|
||||||
var descriptor = new MTLComputePassDescriptor();
|
var descriptor = new MTLComputePassDescriptor();
|
||||||
var computeCommandEncoder = _pipeline.CommandBuffer.ComputeCommandEncoder(descriptor);
|
var computeCommandEncoder = _pipeline.CommandBuffer.ComputeCommandEncoder(descriptor);
|
||||||
|
|
||||||
// Rebind all the state
|
// Mark all state as dirty to ensure it is set on the encoder
|
||||||
SetComputeBuffers(computeCommandEncoder, _currentState.UniformBuffers);
|
_currentState.Dirty |= DirtyFlags.ComputeAll;
|
||||||
SetComputeBuffers(computeCommandEncoder, _currentState.StorageBuffers);
|
|
||||||
for (ulong i = 0; i < Constants.MaxTextures; i++)
|
|
||||||
{
|
|
||||||
SetComputeTexture(computeCommandEncoder, i, _currentState.ComputeTextures[i]);
|
|
||||||
}
|
|
||||||
for (ulong i = 0; i < Constants.MaxSamplers; i++)
|
|
||||||
{
|
|
||||||
SetComputeSampler(computeCommandEncoder, i, _currentState.ComputeSamplers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
descriptor.Dispose();
|
descriptor.Dispose();
|
||||||
|
@ -220,33 +176,93 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public void RebindRenderState(MTLRenderCommandEncoder renderCommandEncoder)
|
public void RebindRenderState(MTLRenderCommandEncoder renderCommandEncoder)
|
||||||
{
|
{
|
||||||
if (_currentState.Dirty.RenderPipeline)
|
if (_currentState.Dirty.HasFlag(DirtyFlags.RenderPipeline))
|
||||||
{
|
{
|
||||||
SetRenderPipelineState(renderCommandEncoder);
|
SetRenderPipelineState(renderCommandEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentState.Dirty.DepthStencil)
|
if (_currentState.Dirty.HasFlag(DirtyFlags.DepthStencil))
|
||||||
{
|
{
|
||||||
SetDepthStencilState(renderCommandEncoder);
|
SetDepthStencilState(renderCommandEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the dirty flags
|
if (_currentState.Dirty.HasFlag(DirtyFlags.DepthClamp))
|
||||||
_currentState.Dirty.RenderPipeline = false;
|
{
|
||||||
_currentState.Dirty.DepthStencil = false;
|
SetDepthClamp(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.DepthBias))
|
||||||
|
{
|
||||||
|
SetDepthBias(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.CullMode))
|
||||||
|
{
|
||||||
|
SetCullMode(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.FrontFace))
|
||||||
|
{
|
||||||
|
SetFrontFace(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.StencilRef))
|
||||||
|
{
|
||||||
|
SetStencilRefValue(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.Viewports))
|
||||||
|
{
|
||||||
|
SetViewports(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.Scissors))
|
||||||
|
{
|
||||||
|
SetScissors(renderCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.VertexBuffers))
|
||||||
|
{
|
||||||
|
SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.Buffers))
|
||||||
|
{
|
||||||
|
SetRenderBuffers(renderCommandEncoder, _currentState.UniformBuffers, _currentState.StorageBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.VertexTextures))
|
||||||
|
{
|
||||||
|
SetRenderTextures(renderCommandEncoder, ShaderStage.Vertex, _currentState.VertexTextures, _currentState.VertexSamplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.FragmentTextures))
|
||||||
|
{
|
||||||
|
SetRenderTextures(renderCommandEncoder, ShaderStage.Fragment, _currentState.FragmentTextures, _currentState.FragmentSamplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentState.Dirty &= ~DirtyFlags.RenderAll;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RebindComputeState(MTLComputeCommandEncoder computeCommandEncoder)
|
public void RebindComputeState(MTLComputeCommandEncoder computeCommandEncoder)
|
||||||
{
|
{
|
||||||
if (_currentState.Dirty.ComputePipeline)
|
if (_currentState.Dirty.HasFlag(DirtyFlags.ComputePipeline))
|
||||||
{
|
{
|
||||||
SetComputePipelineState(computeCommandEncoder);
|
SetComputePipelineState(computeCommandEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the dirty flags
|
if (_currentState.Dirty.HasFlag(DirtyFlags.Buffers))
|
||||||
_currentState.Dirty.ComputePipeline = false;
|
{
|
||||||
|
SetComputeBuffers(computeCommandEncoder, _currentState.UniformBuffers, _currentState.StorageBuffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentState.Dirty.HasFlag(DirtyFlags.ComputeTextures))
|
||||||
|
{
|
||||||
|
SetComputeTextures(computeCommandEncoder, _currentState.ComputeTextures, _currentState.ComputeSamplers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void SetRenderPipelineState(MTLRenderCommandEncoder renderCommandEncoder)
|
private void SetRenderPipelineState(MTLRenderCommandEncoder renderCommandEncoder)
|
||||||
{
|
{
|
||||||
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
|
var renderPipelineDescriptor = new MTLRenderPipelineDescriptor();
|
||||||
|
|
||||||
|
@ -340,7 +356,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void SetComputePipelineState(MTLComputeCommandEncoder computeCommandEncoder)
|
private void SetComputePipelineState(MTLComputeCommandEncoder computeCommandEncoder)
|
||||||
{
|
{
|
||||||
if (_currentState.ComputeFunction == null)
|
if (_currentState.ComputeFunction == null)
|
||||||
{
|
{
|
||||||
|
@ -398,15 +414,13 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_currentState.VertexFunction = prg.VertexFunction;
|
_currentState.VertexFunction = prg.VertexFunction;
|
||||||
_currentState.FragmentFunction = prg.FragmentFunction;
|
_currentState.FragmentFunction = prg.FragmentFunction;
|
||||||
|
|
||||||
// Mark dirty
|
_currentState.Dirty |= DirtyFlags.RenderPipeline;
|
||||||
_currentState.Dirty.RenderPipeline = true;
|
|
||||||
}
|
}
|
||||||
if (prg.ComputeFunction != IntPtr.Zero)
|
if (prg.ComputeFunction != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
_currentState.ComputeFunction = prg.ComputeFunction;
|
_currentState.ComputeFunction = prg.ComputeFunction;
|
||||||
|
|
||||||
// Mark dirty
|
_currentState.Dirty |= DirtyFlags.ComputePipeline;
|
||||||
_currentState.Dirty.ComputePipeline = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,7 +487,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_currentState.VertexAttribs = vertexAttribs.ToArray();
|
_currentState.VertexAttribs = vertexAttribs.ToArray();
|
||||||
|
|
||||||
// Mark dirty
|
// Mark dirty
|
||||||
_currentState.Dirty.RenderPipeline = true;
|
_currentState.Dirty |= DirtyFlags.RenderPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBlendDescriptors(int index, BlendDescriptor blend)
|
public void UpdateBlendDescriptors(int index, BlendDescriptor blend)
|
||||||
|
@ -524,13 +538,12 @@ namespace Ryujinx.Graphics.Metal
|
||||||
UpdateStencilRefValue(stencilTest.FrontFuncRef, stencilTest.BackFuncRef);
|
UpdateStencilRefValue(stencilTest.FrontFuncRef, stencilTest.BackFuncRef);
|
||||||
|
|
||||||
// Mark dirty
|
// Mark dirty
|
||||||
_currentState.Dirty.DepthStencil = true;
|
_currentState.Dirty |= DirtyFlags.DepthStencil;
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
descriptor.Dispose();
|
descriptor.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
|
||||||
public void UpdateDepthState(DepthTestDescriptor depthTest)
|
public void UpdateDepthState(DepthTestDescriptor depthTest)
|
||||||
{
|
{
|
||||||
_currentState.DepthCompareFunction = depthTest.TestEnable ? depthTest.Func.Convert() : MTLCompareFunction.Always;
|
_currentState.DepthCompareFunction = depthTest.TestEnable ? depthTest.Func.Convert() : MTLCompareFunction.Always;
|
||||||
|
@ -551,7 +564,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_currentState.DepthStencilState = _depthStencilCache.GetOrCreate(descriptor);
|
_currentState.DepthStencilState = _depthStencilCache.GetOrCreate(descriptor);
|
||||||
|
|
||||||
// Mark dirty
|
// Mark dirty
|
||||||
_currentState.Dirty.DepthStencil = true;
|
_currentState.Dirty |= DirtyFlags.DepthStencil;
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
descriptor.Dispose();
|
descriptor.Dispose();
|
||||||
|
@ -567,7 +580,11 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetDepthClamp(renderCommandEncoder);
|
SetDepthClamp(renderCommandEncoder);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.DepthClamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
// Inlineable
|
||||||
|
@ -582,7 +599,11 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetDepthBias(renderCommandEncoder);
|
SetDepthBias(renderCommandEncoder);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.DepthBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
// Inlineable
|
||||||
|
@ -610,7 +631,11 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetScissors(renderCommandEncoder);
|
SetScissors(renderCommandEncoder);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.Scissors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
// Inlineable
|
||||||
|
@ -643,7 +668,11 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetViewports(renderCommandEncoder);
|
SetViewports(renderCommandEncoder);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.Viewports;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
|
public void UpdateVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
|
||||||
|
@ -655,20 +684,17 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers);
|
SetVertexBuffers(renderCommandEncoder, _currentState.VertexBuffers);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark dirty
|
// Mark dirty
|
||||||
_currentState.Dirty.RenderPipeline = true;
|
_currentState.Dirty |= DirtyFlags.RenderPipeline | DirtyFlags.VertexBuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
|
||||||
public void UpdateUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
public void UpdateUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||||
{
|
{
|
||||||
_currentState.UniformBuffers = new BufferRef[buffers.Length];
|
foreach (BufferAssignment assignment in buffers)
|
||||||
|
|
||||||
for (int i = 0; i < buffers.Length; i++)
|
|
||||||
{
|
{
|
||||||
var assignment = buffers[i];
|
|
||||||
var buffer = assignment.Range;
|
var buffer = assignment.Range;
|
||||||
int index = assignment.Binding;
|
int index = assignment.Binding;
|
||||||
|
|
||||||
|
@ -676,87 +702,40 @@ namespace Ryujinx.Graphics.Metal
|
||||||
? null
|
? null
|
||||||
: _bufferManager.GetBuffer(buffer.Handle, buffer.Write);
|
: _bufferManager.GetBuffer(buffer.Handle, buffer.Write);
|
||||||
|
|
||||||
_currentState.UniformBuffers[i] = new BufferRef(mtlBuffer, index, ref buffer);
|
_currentState.UniformBuffers[index] = new BufferRef(mtlBuffer, ref buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline update
|
_currentState.Dirty |= DirtyFlags.Buffers;
|
||||||
if (_pipeline.CurrentEncoder != null)
|
|
||||||
{
|
|
||||||
if (_pipeline.CurrentEncoderType == EncoderType.Render)
|
|
||||||
{
|
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.UniformBuffers, true);
|
|
||||||
}
|
|
||||||
else if (_pipeline.CurrentEncoderType == EncoderType.Compute)
|
|
||||||
{
|
|
||||||
var computeCommandEncoder = new MTLComputeCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetComputeBuffers(computeCommandEncoder, _currentState.UniformBuffers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
|
||||||
public void UpdateStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
public void UpdateStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||||
{
|
{
|
||||||
_currentState.StorageBuffers = new BufferRef[buffers.Length];
|
foreach (BufferAssignment assignment in buffers)
|
||||||
|
|
||||||
for (int i = 0; i < buffers.Length; i++)
|
|
||||||
{
|
{
|
||||||
var assignment = buffers[i];
|
|
||||||
var buffer = assignment.Range;
|
var buffer = assignment.Range;
|
||||||
// TODO: Dont do this
|
int index = assignment.Binding;
|
||||||
int index = assignment.Binding + 15;
|
|
||||||
|
|
||||||
Auto<DisposableBuffer> mtlBuffer = buffer.Handle == BufferHandle.Null
|
Auto<DisposableBuffer> mtlBuffer = buffer.Handle == BufferHandle.Null
|
||||||
? null
|
? null
|
||||||
: _bufferManager.GetBuffer(buffer.Handle, buffer.Write);
|
: _bufferManager.GetBuffer(buffer.Handle, buffer.Write);
|
||||||
|
|
||||||
_currentState.StorageBuffers[i] = new BufferRef(mtlBuffer, index, ref buffer);
|
_currentState.StorageBuffers[index] = new BufferRef(mtlBuffer, ref buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline update
|
_currentState.Dirty |= DirtyFlags.Buffers;
|
||||||
if (_pipeline.CurrentEncoder != null)
|
|
||||||
{
|
|
||||||
if (_pipeline.CurrentEncoderType == EncoderType.Render)
|
|
||||||
{
|
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.StorageBuffers, true);
|
|
||||||
}
|
|
||||||
else if (_pipeline.CurrentEncoderType == EncoderType.Compute)
|
|
||||||
{
|
|
||||||
var computeCommandEncoder = new MTLComputeCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetComputeBuffers(computeCommandEncoder, _currentState.StorageBuffers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
|
||||||
public void UpdateStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
|
public void UpdateStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
|
||||||
{
|
{
|
||||||
_currentState.StorageBuffers = new BufferRef[buffers.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < buffers.Length; i++)
|
for (int i = 0; i < buffers.Length; i++)
|
||||||
{
|
{
|
||||||
var mtlBuffer = buffers[i];
|
var mtlBuffer = buffers[i];
|
||||||
int index = first + i;
|
int index = first + i;
|
||||||
|
|
||||||
_currentState.StorageBuffers[i] = new BufferRef(mtlBuffer, index);
|
_currentState.StorageBuffers[index] = new BufferRef(mtlBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline update
|
_currentState.Dirty |= DirtyFlags.Buffers;
|
||||||
if (_pipeline.CurrentEncoder != null)
|
|
||||||
{
|
|
||||||
if (_pipeline.CurrentEncoderType == EncoderType.Render)
|
|
||||||
{
|
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetRenderBuffers(renderCommandEncoder, _currentState.StorageBuffers, true);
|
|
||||||
}
|
|
||||||
else if (_pipeline.CurrentEncoderType == EncoderType.Compute)
|
|
||||||
{
|
|
||||||
var computeCommandEncoder = new MTLComputeCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetComputeBuffers(computeCommandEncoder, _currentState.StorageBuffers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
// Inlineable
|
||||||
|
@ -769,7 +748,11 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetCullMode(renderCommandEncoder);
|
SetCullMode(renderCommandEncoder);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.CullMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
// Inlineable
|
||||||
|
@ -782,7 +765,11 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetFrontFace(renderCommandEncoder);
|
SetFrontFace(renderCommandEncoder);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.FrontFace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateStencilRefValue(int frontRef, int backRef)
|
private void UpdateStencilRefValue(int frontRef, int backRef)
|
||||||
|
@ -796,84 +783,60 @@ namespace Ryujinx.Graphics.Metal
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
||||||
SetStencilRefValue(renderCommandEncoder);
|
SetStencilRefValue(renderCommandEncoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark dirty
|
||||||
|
_currentState.Dirty |= DirtyFlags.StencilRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
public void UpdateTexture(ShaderStage stage, ulong binding, TextureBase texture)
|
||||||
public readonly void UpdateTexture(ShaderStage stage, ulong binding, TextureBase texture)
|
|
||||||
{
|
{
|
||||||
if (binding > 30)
|
if (binding > Constants.MaxTexturesPerStage)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Gpu, $"Texture binding ({binding}) must be <= 30");
|
Logger.Warning?.Print(LogClass.Gpu, $"Texture binding ({binding}) must be <= {Constants.MaxTexturesPerStage}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case ShaderStage.Fragment:
|
case ShaderStage.Fragment:
|
||||||
_currentState.FragmentTextures[binding] = texture;
|
_currentState.FragmentTextures[binding] = texture;
|
||||||
|
_currentState.Dirty |= DirtyFlags.FragmentTextures;
|
||||||
break;
|
break;
|
||||||
case ShaderStage.Vertex:
|
case ShaderStage.Vertex:
|
||||||
_currentState.VertexTextures[binding] = texture;
|
_currentState.VertexTextures[binding] = texture;
|
||||||
|
_currentState.Dirty |= DirtyFlags.VertexTextures;
|
||||||
break;
|
break;
|
||||||
case ShaderStage.Compute:
|
case ShaderStage.Compute:
|
||||||
_currentState.ComputeTextures[binding] = texture;
|
_currentState.ComputeTextures[binding] = texture;
|
||||||
|
_currentState.Dirty |= DirtyFlags.ComputeTextures;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pipeline.CurrentEncoder != null)
|
|
||||||
{
|
|
||||||
if (_pipeline.CurrentEncoderType == EncoderType.Render)
|
|
||||||
{
|
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetRenderTexture(renderCommandEncoder, ShaderStage.Vertex, binding, texture);
|
|
||||||
SetRenderTexture(renderCommandEncoder, ShaderStage.Fragment, binding, texture);
|
|
||||||
}
|
|
||||||
else if (_pipeline.CurrentEncoderType == EncoderType.Compute)
|
|
||||||
{
|
|
||||||
var computeCommandEncoder = new MTLComputeCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetComputeTexture(computeCommandEncoder, binding, texture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
public void UpdateSampler(ShaderStage stage, ulong binding, MTLSamplerState sampler)
|
||||||
public readonly void UpdateSampler(ShaderStage stage, ulong binding, MTLSamplerState sampler)
|
|
||||||
{
|
{
|
||||||
if (binding > 15)
|
if (binding > Constants.MaxTexturesPerStage)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Gpu, $"Sampler binding ({binding}) must be <= 15");
|
Logger.Warning?.Print(LogClass.Gpu, $"Sampler binding ({binding}) must be <= {Constants.MaxTexturesPerStage}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
case ShaderStage.Fragment:
|
case ShaderStage.Fragment:
|
||||||
_currentState.FragmentSamplers[binding] = sampler;
|
_currentState.FragmentSamplers[binding] = sampler;
|
||||||
|
_currentState.Dirty |= DirtyFlags.FragmentTextures;
|
||||||
break;
|
break;
|
||||||
case ShaderStage.Vertex:
|
case ShaderStage.Vertex:
|
||||||
_currentState.VertexSamplers[binding] = sampler;
|
_currentState.VertexSamplers[binding] = sampler;
|
||||||
|
_currentState.Dirty |= DirtyFlags.VertexTextures;
|
||||||
break;
|
break;
|
||||||
case ShaderStage.Compute:
|
case ShaderStage.Compute:
|
||||||
_currentState.ComputeSamplers[binding] = sampler;
|
_currentState.ComputeSamplers[binding] = sampler;
|
||||||
|
_currentState.Dirty |= DirtyFlags.ComputeTextures;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pipeline.CurrentEncoder != null)
|
|
||||||
{
|
|
||||||
if (_pipeline.CurrentEncoderType == EncoderType.Render)
|
|
||||||
{
|
|
||||||
var renderCommandEncoder = new MTLRenderCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetRenderSampler(renderCommandEncoder, ShaderStage.Vertex, binding, sampler);
|
|
||||||
SetRenderSampler(renderCommandEncoder, ShaderStage.Fragment, binding, sampler);
|
|
||||||
}
|
|
||||||
else if (_pipeline.CurrentEncoderType == EncoderType.Compute)
|
|
||||||
{
|
|
||||||
var computeCommandEncoder = new MTLComputeCommandEncoder(_pipeline.CurrentEncoder.Value);
|
|
||||||
SetComputeSampler(computeCommandEncoder, binding, sampler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlineable
|
public void UpdateTextureAndSampler(ShaderStage stage, ulong binding, TextureBase texture, MTLSamplerState sampler)
|
||||||
public readonly void UpdateTextureAndSampler(ShaderStage stage, ulong binding, TextureBase texture, MTLSamplerState sampler)
|
|
||||||
{
|
{
|
||||||
UpdateTexture(stage, binding, texture);
|
UpdateTexture(stage, binding, texture);
|
||||||
UpdateSampler(stage, binding, sampler);
|
UpdateSampler(stage, binding, sampler);
|
||||||
|
@ -930,8 +893,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
var attrib = vertexDescriptor.Attributes.Object((ulong)i);
|
var attrib = vertexDescriptor.Attributes.Object((ulong)i);
|
||||||
attrib.Format = attribDescriptors[i].Format.Convert();
|
attrib.Format = attribDescriptors[i].Format.Convert();
|
||||||
indexMask |= 1u << bufferDescriptors.Length;
|
indexMask |= 1u << (int)Constants.ZeroBufferIndex;
|
||||||
attrib.BufferIndex = (ulong)bufferDescriptors.Length;
|
attrib.BufferIndex = Constants.ZeroBufferIndex;
|
||||||
attrib.Offset = 0;
|
attrib.Offset = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -979,9 +942,9 @@ namespace Ryujinx.Graphics.Metal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero buffer
|
// Zero buffer
|
||||||
if ((indexMask & (1u << bufferDescriptors.Length)) != 0)
|
if ((indexMask & (1u << (int)Constants.ZeroBufferIndex)) != 0)
|
||||||
{
|
{
|
||||||
var layout = vertexDescriptor.Layouts.Object((ulong)bufferDescriptors.Length);
|
var layout = vertexDescriptor.Layouts.Object(Constants.ZeroBufferIndex);
|
||||||
layout.Stride = 1;
|
layout.Stride = 1;
|
||||||
layout.StepFunction = MTLVertexStepFunction.Constant;
|
layout.StepFunction = MTLVertexStepFunction.Constant;
|
||||||
layout.StepRate = 0;
|
layout.StepRate = 0;
|
||||||
|
@ -992,39 +955,77 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
private void SetVertexBuffers(MTLRenderCommandEncoder renderCommandEncoder, VertexBufferDescriptor[] bufferDescriptors)
|
private void SetVertexBuffers(MTLRenderCommandEncoder renderCommandEncoder, VertexBufferDescriptor[] bufferDescriptors)
|
||||||
{
|
{
|
||||||
var buffers = new List<BufferRef>();
|
|
||||||
|
|
||||||
for (int i = 0; i < bufferDescriptors.Length; i++)
|
for (int i = 0; i < bufferDescriptors.Length; i++)
|
||||||
{
|
{
|
||||||
Auto<DisposableBuffer> mtlBuffer = bufferDescriptors[i].Buffer.Handle == BufferHandle.Null
|
Auto<DisposableBuffer> autoBuffer = bufferDescriptors[i].Buffer.Handle == BufferHandle.Null
|
||||||
? null
|
? null
|
||||||
: _bufferManager.GetBuffer(bufferDescriptors[i].Buffer.Handle, bufferDescriptors[i].Buffer.Write);
|
: _bufferManager.GetBuffer(bufferDescriptors[i].Buffer.Handle, bufferDescriptors[i].Buffer.Write);
|
||||||
|
|
||||||
var range = bufferDescriptors[i].Buffer;
|
var range = bufferDescriptors[i].Buffer;
|
||||||
|
var offset = range.Offset;
|
||||||
|
|
||||||
buffers.Add(new BufferRef(mtlBuffer, i, ref range));
|
if (autoBuffer == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mtlBuffer = autoBuffer.Get(_pipeline.Cbs, offset, range.Size, range.Write).Value;
|
||||||
|
renderCommandEncoder.SetVertexBuffer(mtlBuffer, (ulong)offset, (ulong)i);
|
||||||
}
|
}
|
||||||
|
|
||||||
var zeroBufferRange = new BufferRange(_zeroBuffer, 0, ZeroBufferSize);
|
Auto<DisposableBuffer> autoZeroBuffer = _zeroBuffer == BufferHandle.Null
|
||||||
|
|
||||||
Auto<DisposableBuffer> zeroBuffer = _zeroBuffer == BufferHandle.Null
|
|
||||||
? null
|
? null
|
||||||
: _bufferManager.GetBuffer(_zeroBuffer, false);
|
: _bufferManager.GetBuffer(_zeroBuffer, false);
|
||||||
|
|
||||||
// Zero buffer
|
if (autoZeroBuffer == null)
|
||||||
buffers.Add(new BufferRef(zeroBuffer, bufferDescriptors.Length, ref zeroBufferRange));
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SetRenderBuffers(renderCommandEncoder, buffers.ToArray());
|
var zeroMtlBuffer = autoZeroBuffer.Get(_pipeline.Cbs).Value;
|
||||||
|
renderCommandEncoder.SetVertexBuffer(zeroMtlBuffer, 0, Constants.ZeroBufferIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void SetRenderBuffers(MTLRenderCommandEncoder renderCommandEncoder, BufferRef[] buffers, bool fragment = false)
|
private readonly void SetRenderBuffers(MTLRenderCommandEncoder renderCommandEncoder, BufferRef[] uniformBuffers, BufferRef[] storageBuffers)
|
||||||
{
|
{
|
||||||
|
var uniformArgBufferRange = CreateArgumentBufferForRenderEncoder(renderCommandEncoder, uniformBuffers, true);
|
||||||
|
var uniformArgBuffer = _bufferManager.GetBuffer(uniformArgBufferRange.Handle, false).Get(_pipeline.Cbs).Value;
|
||||||
|
|
||||||
|
renderCommandEncoder.SetVertexBuffer(uniformArgBuffer, (ulong)uniformArgBufferRange.Offset, Constants.ConstantBuffersIndex);
|
||||||
|
renderCommandEncoder.SetFragmentBuffer(uniformArgBuffer, (ulong)uniformArgBufferRange.Offset, Constants.ConstantBuffersIndex);
|
||||||
|
|
||||||
|
var storageArgBufferRange = CreateArgumentBufferForRenderEncoder(renderCommandEncoder, storageBuffers, false);
|
||||||
|
var storageArgBuffer = _bufferManager.GetBuffer(storageArgBufferRange.Handle, true).Get(_pipeline.Cbs).Value;
|
||||||
|
|
||||||
|
renderCommandEncoder.SetVertexBuffer(storageArgBuffer, (ulong)storageArgBufferRange.Offset, Constants.StorageBuffersIndex);
|
||||||
|
renderCommandEncoder.SetFragmentBuffer(storageArgBuffer, (ulong)storageArgBufferRange.Offset, Constants.StorageBuffersIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly void SetComputeBuffers(MTLComputeCommandEncoder computeCommandEncoder, BufferRef[] uniformBuffers, BufferRef[] storageBuffers)
|
||||||
|
{
|
||||||
|
var uniformArgBufferRange = CreateArgumentBufferForComputeEncoder(computeCommandEncoder, uniformBuffers, true);
|
||||||
|
var uniformArgBuffer = _bufferManager.GetBuffer(uniformArgBufferRange.Handle, false).Get(_pipeline.Cbs).Value;
|
||||||
|
|
||||||
|
computeCommandEncoder.SetBuffer(uniformArgBuffer, (ulong)uniformArgBufferRange.Offset, Constants.ConstantBuffersIndex);
|
||||||
|
|
||||||
|
|
||||||
|
var storageArgBufferRange = CreateArgumentBufferForComputeEncoder(computeCommandEncoder, storageBuffers, false);
|
||||||
|
var storageArgBuffer = _bufferManager.GetBuffer(storageArgBufferRange.Handle, true).Get(_pipeline.Cbs).Value;
|
||||||
|
|
||||||
|
computeCommandEncoder.SetBuffer(storageArgBuffer, (ulong)storageArgBufferRange.Offset, Constants.StorageBuffersIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly BufferRange CreateArgumentBufferForRenderEncoder(MTLRenderCommandEncoder renderCommandEncoder, BufferRef[] buffers, bool constant)
|
||||||
|
{
|
||||||
|
var usage = constant ? MTLResourceUsage.Read : MTLResourceUsage.Write;
|
||||||
|
|
||||||
|
ulong[] resourceIds = new ulong[buffers.Length];
|
||||||
|
|
||||||
for (int i = 0; i < buffers.Length; i++)
|
for (int i = 0; i < buffers.Length; i++)
|
||||||
{
|
{
|
||||||
var range = buffers[i].Range;
|
var range = buffers[i].Range;
|
||||||
var autoBuffer = buffers[i].Buffer;
|
var autoBuffer = buffers[i].Buffer;
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var index = buffers[i].Index;
|
|
||||||
|
|
||||||
if (autoBuffer == null)
|
if (autoBuffer == null)
|
||||||
{
|
{
|
||||||
|
@ -1044,23 +1045,29 @@ namespace Ryujinx.Graphics.Metal
|
||||||
mtlBuffer = autoBuffer.Get(_pipeline.Cbs).Value;
|
mtlBuffer = autoBuffer.Get(_pipeline.Cbs).Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderCommandEncoder.SetVertexBuffer(mtlBuffer, (ulong)offset, (ulong)index);
|
renderCommandEncoder.UseResource(new MTLResource(mtlBuffer.NativePtr), usage, MTLRenderStages.RenderStageFragment | MTLRenderStages.RenderStageVertex);
|
||||||
|
resourceIds[i] = mtlBuffer.GpuAddress + (ulong)offset;
|
||||||
if (fragment)
|
|
||||||
{
|
|
||||||
renderCommandEncoder.SetFragmentBuffer(mtlBuffer, (ulong)offset, (ulong)index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sizeOfArgumentBuffer = sizeof(ulong) * buffers.Length;
|
||||||
|
|
||||||
|
var argBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, sizeOfArgumentBuffer);
|
||||||
|
argBuffer.Holder.SetDataUnchecked(argBuffer.Offset, new ReadOnlySpan<ulong>(resourceIds));
|
||||||
|
|
||||||
|
return argBuffer.Range;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void SetComputeBuffers(MTLComputeCommandEncoder computeCommandEncoder, BufferRef[] buffers)
|
private readonly BufferRange CreateArgumentBufferForComputeEncoder(MTLComputeCommandEncoder computeCommandEncoder, BufferRef[] buffers, bool constant)
|
||||||
{
|
{
|
||||||
|
var usage = constant ? MTLResourceUsage.Read : MTLResourceUsage.Write;
|
||||||
|
|
||||||
|
ulong[] resourceIds = new ulong[buffers.Length];
|
||||||
|
|
||||||
for (int i = 0; i < buffers.Length; i++)
|
for (int i = 0; i < buffers.Length; i++)
|
||||||
{
|
{
|
||||||
var range = buffers[i].Range;
|
var range = buffers[i].Range;
|
||||||
var autoBuffer = buffers[i].Buffer;
|
var autoBuffer = buffers[i].Buffer;
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
var index = buffers[i].Index;
|
|
||||||
|
|
||||||
if (autoBuffer == null)
|
if (autoBuffer == null)
|
||||||
{
|
{
|
||||||
|
@ -1080,8 +1087,16 @@ namespace Ryujinx.Graphics.Metal
|
||||||
mtlBuffer = autoBuffer.Get(_pipeline.Cbs).Value;
|
mtlBuffer = autoBuffer.Get(_pipeline.Cbs).Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
computeCommandEncoder.SetBuffer(mtlBuffer, (ulong)offset, (ulong)index);
|
computeCommandEncoder.UseResource(new MTLResource(mtlBuffer.NativePtr), usage);
|
||||||
|
resourceIds[i] = mtlBuffer.GpuAddress + (ulong)offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sizeOfArgumentBuffer = sizeof(ulong) * buffers.Length;
|
||||||
|
|
||||||
|
var argBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, sizeOfArgumentBuffer);
|
||||||
|
argBuffer.Holder.SetDataUnchecked(argBuffer.Offset, new ReadOnlySpan<ulong>(resourceIds));
|
||||||
|
|
||||||
|
return argBuffer.Range;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void SetCullMode(MTLRenderCommandEncoder renderCommandEncoder)
|
private readonly void SetCullMode(MTLRenderCommandEncoder renderCommandEncoder)
|
||||||
|
@ -1099,64 +1114,104 @@ namespace Ryujinx.Graphics.Metal
|
||||||
renderCommandEncoder.SetStencilReferenceValues((uint)_currentState.FrontRefValue, (uint)_currentState.BackRefValue);
|
renderCommandEncoder.SetStencilReferenceValues((uint)_currentState.FrontRefValue, (uint)_currentState.BackRefValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetRenderTexture(MTLRenderCommandEncoder renderCommandEncoder, ShaderStage stage, ulong binding, TextureBase texture)
|
private readonly void SetRenderTextures(MTLRenderCommandEncoder renderCommandEncoder, ShaderStage stage, TextureBase[] textures, MTLSamplerState[] samplers)
|
||||||
{
|
{
|
||||||
if (texture == null)
|
var argBufferRange = CreateArgumentBufferForRenderEncoder(renderCommandEncoder, stage, textures, samplers);
|
||||||
{
|
var argBuffer = _bufferManager.GetBuffer(argBufferRange.Handle, false).Get(_pipeline.Cbs).Value;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var textureHandle = texture.GetHandle();
|
switch (stage)
|
||||||
if (textureHandle != IntPtr.Zero)
|
|
||||||
{
|
{
|
||||||
switch (stage)
|
case ShaderStage.Vertex:
|
||||||
|
renderCommandEncoder.SetVertexBuffer(argBuffer, (ulong)argBufferRange.Offset, Constants.TexturesIndex);
|
||||||
|
break;
|
||||||
|
case ShaderStage.Fragment:
|
||||||
|
renderCommandEncoder.SetFragmentBuffer(argBuffer, (ulong)argBufferRange.Offset, Constants.TexturesIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly void SetComputeTextures(MTLComputeCommandEncoder computeCommandEncoder, TextureBase[] textures, MTLSamplerState[] samplers)
|
||||||
|
{
|
||||||
|
var argBufferRange = CreateArgumentBufferForComputeEncoder(computeCommandEncoder, textures, samplers);
|
||||||
|
var argBuffer = _bufferManager.GetBuffer(argBufferRange.Handle, false).Get(_pipeline.Cbs).Value;
|
||||||
|
|
||||||
|
computeCommandEncoder.SetBuffer(argBuffer, (ulong)argBufferRange.Offset, Constants.TexturesIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly BufferRange CreateArgumentBufferForRenderEncoder(MTLRenderCommandEncoder renderCommandEncoder, ShaderStage stage, TextureBase[] textures, MTLSamplerState[] samplers)
|
||||||
|
{
|
||||||
|
var renderStage = stage == ShaderStage.Vertex ? MTLRenderStages.RenderStageVertex : MTLRenderStages.RenderStageFragment;
|
||||||
|
|
||||||
|
ulong[] resourceIds = new ulong[textures.Length + samplers.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < textures.Length; i++)
|
||||||
|
{
|
||||||
|
if (textures[i] == null)
|
||||||
{
|
{
|
||||||
case ShaderStage.Vertex:
|
continue;
|
||||||
renderCommandEncoder.SetVertexTexture(textureHandle, binding);
|
|
||||||
break;
|
|
||||||
case ShaderStage.Fragment:
|
|
||||||
renderCommandEncoder.SetFragmentTexture(textureHandle, binding);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetRenderSampler(MTLRenderCommandEncoder renderCommandEncoder, ShaderStage stage, ulong binding, MTLSamplerState sampler)
|
var mtlTexture = textures[i].GetHandle();
|
||||||
{
|
|
||||||
if (sampler != IntPtr.Zero)
|
renderCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), MTLResourceUsage.Read, renderStage);
|
||||||
|
resourceIds[i] = mtlTexture.GpuResourceID._impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < samplers.Length; i++)
|
||||||
{
|
{
|
||||||
switch (stage)
|
if (samplers[i].NativePtr == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
case ShaderStage.Vertex:
|
continue;
|
||||||
renderCommandEncoder.SetVertexSamplerState(sampler, binding);
|
|
||||||
break;
|
|
||||||
case ShaderStage.Fragment:
|
|
||||||
renderCommandEncoder.SetFragmentSamplerState(sampler, binding);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sampler = samplers[i];
|
||||||
|
|
||||||
|
resourceIds[i + textures.Length] = sampler.GpuResourceID._impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sizeOfArgumentBuffer = sizeof(ulong) * (textures.Length + samplers.Length);
|
||||||
|
|
||||||
|
var argBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, sizeOfArgumentBuffer);
|
||||||
|
argBuffer.Holder.SetDataUnchecked(argBuffer.Offset, new ReadOnlySpan<ulong>(resourceIds));
|
||||||
|
|
||||||
|
return argBuffer.Range;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetComputeTexture(MTLComputeCommandEncoder computeCommandEncoder, ulong binding, TextureBase texture)
|
private readonly BufferRange CreateArgumentBufferForComputeEncoder(MTLComputeCommandEncoder computeCommandEncoder, TextureBase[] textures, MTLSamplerState[] samplers)
|
||||||
{
|
{
|
||||||
if (texture == null)
|
ulong[] resourceIds = new ulong[textures.Length + samplers.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < textures.Length; i++)
|
||||||
{
|
{
|
||||||
return;
|
if (textures[i] == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mtlTexture = textures[i].GetHandle();
|
||||||
|
|
||||||
|
computeCommandEncoder.UseResource(new MTLResource(mtlTexture.NativePtr), MTLResourceUsage.Read);
|
||||||
|
resourceIds[i] = mtlTexture.GpuResourceID._impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textureHandle = texture.GetHandle();
|
for (int i = 0; i < samplers.Length; i++)
|
||||||
if (textureHandle != IntPtr.Zero)
|
|
||||||
{
|
{
|
||||||
computeCommandEncoder.SetTexture(textureHandle, binding);
|
if (samplers[i].NativePtr == IntPtr.Zero)
|
||||||
}
|
{
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
private static void SetComputeSampler(MTLComputeCommandEncoder computeCommandEncoder, ulong binding, MTLSamplerState sampler)
|
var sampler = samplers[i];
|
||||||
{
|
|
||||||
if (sampler != IntPtr.Zero)
|
resourceIds[i + textures.Length] = sampler.GpuResourceID._impl;
|
||||||
{
|
|
||||||
computeCommandEncoder.SetSamplerState(sampler, binding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sizeOfArgumentBuffer = sizeof(ulong) * (textures.Length + samplers.Length);
|
||||||
|
|
||||||
|
var argBuffer = _bufferManager.ReserveOrCreate(_pipeline.Cbs, sizeOfArgumentBuffer);
|
||||||
|
argBuffer.Holder.SetDataUnchecked(argBuffer.Offset, new ReadOnlySpan<ulong>(resourceIds));
|
||||||
|
|
||||||
|
return argBuffer.Range;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
ITexture dst,
|
ITexture dst,
|
||||||
Extents2D srcRegion,
|
Extents2D srcRegion,
|
||||||
Extents2D dstRegion,
|
Extents2D dstRegion,
|
||||||
bool linearFilter)
|
bool linearFilter,
|
||||||
|
bool clear = false)
|
||||||
{
|
{
|
||||||
// Save current state
|
// Save current state
|
||||||
_pipeline.SaveAndResetState();
|
_pipeline.SaveAndResetState();
|
||||||
|
@ -134,7 +135,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_pipeline.SetRenderTargets([dst], null);
|
_pipeline.SetRenderTargets([dst], null);
|
||||||
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dstWidth, dstHeight) });
|
_pipeline.SetScissors(stackalloc Rectangle<int>[] { new Rectangle<int>(0, 0, dstWidth, dstHeight) });
|
||||||
|
|
||||||
_pipeline.SetClearLoadAction(true);
|
_pipeline.SetClearLoadAction(clear);
|
||||||
|
|
||||||
_pipeline.SetViewports(viewports);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
|
@ -305,13 +306,15 @@ namespace Ryujinx.Graphics.Metal
|
||||||
int dstWidth,
|
int dstWidth,
|
||||||
int dstHeight)
|
int dstHeight)
|
||||||
{
|
{
|
||||||
const int ClearDepthBufferSize = 4;
|
|
||||||
|
|
||||||
IntPtr ptr = new(&depthValue);
|
|
||||||
|
|
||||||
// Save current state
|
// Save current state
|
||||||
_pipeline.SaveState();
|
_pipeline.SaveState();
|
||||||
|
|
||||||
|
const int ClearDepthBufferSize = 4;
|
||||||
|
|
||||||
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearDepthBufferSize);
|
||||||
|
buffer.Holder.SetDataUnchecked(buffer.Offset, new ReadOnlySpan<float>(ref depthValue));
|
||||||
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
viewports[0] = new Viewport(
|
viewports[0] = new Viewport(
|
||||||
|
@ -330,7 +333,6 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_pipeline.SetViewports(viewports);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
|
||||||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
|
||||||
_pipeline.GetOrCreateRenderEncoder(true).SetFragmentBytes(ptr, ClearDepthBufferSize, 0);
|
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
|
|
||||||
// Restore previous state
|
// Restore previous state
|
||||||
|
|
|
@ -104,7 +104,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
return BeginBlitPass();
|
return BeginBlitPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MTLComputeCommandEncoder GetOrCreateComputeEncoder()
|
public MTLComputeCommandEncoder GetOrCreateComputeEncoder(bool forDispatch = false)
|
||||||
{
|
{
|
||||||
MTLComputeCommandEncoder computeCommandEncoder;
|
MTLComputeCommandEncoder computeCommandEncoder;
|
||||||
if (CurrentEncoder == null || CurrentEncoderType != EncoderType.Compute)
|
if (CurrentEncoder == null || CurrentEncoderType != EncoderType.Compute)
|
||||||
|
@ -116,7 +116,10 @@ namespace Ryujinx.Graphics.Metal
|
||||||
computeCommandEncoder = new MTLComputeCommandEncoder(CurrentEncoder.Value);
|
computeCommandEncoder = new MTLComputeCommandEncoder(CurrentEncoder.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
_encoderStateManager.RebindComputeState(computeCommandEncoder);
|
if (forDispatch)
|
||||||
|
{
|
||||||
|
_encoderStateManager.RebindComputeState(computeCommandEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
return computeCommandEncoder;
|
return computeCommandEncoder;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +193,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
var textureInfo = new TextureCreateInfo((int)drawable.Texture.Width, (int)drawable.Texture.Height, (int)drawable.Texture.Depth, (int)drawable.Texture.MipmapLevelCount, (int)drawable.Texture.SampleCount, 0, 0, 0, Format.B8G8R8A8Unorm, 0, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha);
|
var textureInfo = new TextureCreateInfo((int)drawable.Texture.Width, (int)drawable.Texture.Height, (int)drawable.Texture.Depth, (int)drawable.Texture.MipmapLevelCount, (int)drawable.Texture.SampleCount, 0, 0, 0, Format.B8G8R8A8Unorm, 0, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha);
|
||||||
var dst = new Texture(_device, _renderer, this, textureInfo, drawable.Texture, 0, 0);
|
var dst = new Texture(_device, _renderer, this, textureInfo, drawable.Texture, 0, 0);
|
||||||
|
|
||||||
_renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, isLinear);
|
_renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, isLinear, true);
|
||||||
|
|
||||||
EndCurrentPass();
|
EndCurrentPass();
|
||||||
|
|
||||||
|
@ -348,7 +351,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
|
public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
|
||||||
{
|
{
|
||||||
var computeCommandEncoder = GetOrCreateComputeEncoder();
|
var computeCommandEncoder = GetOrCreateComputeEncoder(true);
|
||||||
|
|
||||||
computeCommandEncoder.DispatchThreadgroups(
|
computeCommandEncoder.DispatchThreadgroups(
|
||||||
new MTLSize { width = (ulong)groupsX, height = (ulong)groupsY, depth = (ulong)groupsZ },
|
new MTLSize { width = (ulong)groupsX, height = (ulong)groupsY, depth = (ulong)groupsZ },
|
||||||
|
|
|
@ -27,7 +27,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
MaxAnisotropy = Math.Max((uint)info.MaxAnisotropy, 1),
|
MaxAnisotropy = Math.Max((uint)info.MaxAnisotropy, 1),
|
||||||
SAddressMode = info.AddressU.Convert(),
|
SAddressMode = info.AddressU.Convert(),
|
||||||
TAddressMode = info.AddressV.Convert(),
|
TAddressMode = info.AddressV.Convert(),
|
||||||
RAddressMode = info.AddressP.Convert()
|
RAddressMode = info.AddressP.Convert(),
|
||||||
|
SupportArgumentBuffers = true
|
||||||
});
|
});
|
||||||
|
|
||||||
_mtlSamplerState = samplerState;
|
_mtlSamplerState = samplerState;
|
||||||
|
|
|
@ -7,14 +7,154 @@ struct CopyVertexOut {
|
||||||
float2 uv;
|
float2 uv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TexCoords {
|
||||||
|
float data[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstantBuffers {
|
||||||
|
constant TexCoords* texCoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Textures
|
||||||
|
{
|
||||||
|
texture2d<float, access::sample> texture;
|
||||||
|
ulong padding_1;
|
||||||
|
ulong padding_2;
|
||||||
|
ulong padding_3;
|
||||||
|
ulong padding_4;
|
||||||
|
ulong padding_5;
|
||||||
|
ulong padding_6;
|
||||||
|
ulong padding_7;
|
||||||
|
ulong padding_8;
|
||||||
|
ulong padding_9;
|
||||||
|
ulong padding_10;
|
||||||
|
ulong padding_11;
|
||||||
|
ulong padding_12;
|
||||||
|
ulong padding_13;
|
||||||
|
ulong padding_14;
|
||||||
|
ulong padding_15;
|
||||||
|
ulong padding_16;
|
||||||
|
ulong padding_17;
|
||||||
|
ulong padding_18;
|
||||||
|
ulong padding_19;
|
||||||
|
ulong padding_20;
|
||||||
|
ulong padding_21;
|
||||||
|
ulong padding_22;
|
||||||
|
ulong padding_23;
|
||||||
|
ulong padding_24;
|
||||||
|
ulong padding_25;
|
||||||
|
ulong padding_26;
|
||||||
|
ulong padding_27;
|
||||||
|
ulong padding_28;
|
||||||
|
ulong padding_29;
|
||||||
|
ulong padding_30;
|
||||||
|
ulong padding_31;
|
||||||
|
ulong padding_32;
|
||||||
|
ulong padding_33;
|
||||||
|
ulong padding_34;
|
||||||
|
ulong padding_35;
|
||||||
|
ulong padding_36;
|
||||||
|
ulong padding_37;
|
||||||
|
ulong padding_38;
|
||||||
|
ulong padding_39;
|
||||||
|
ulong padding_40;
|
||||||
|
ulong padding_41;
|
||||||
|
ulong padding_42;
|
||||||
|
ulong padding_43;
|
||||||
|
ulong padding_44;
|
||||||
|
ulong padding_45;
|
||||||
|
ulong padding_46;
|
||||||
|
ulong padding_47;
|
||||||
|
ulong padding_48;
|
||||||
|
ulong padding_49;
|
||||||
|
ulong padding_50;
|
||||||
|
ulong padding_51;
|
||||||
|
ulong padding_52;
|
||||||
|
ulong padding_53;
|
||||||
|
ulong padding_54;
|
||||||
|
ulong padding_55;
|
||||||
|
ulong padding_56;
|
||||||
|
ulong padding_57;
|
||||||
|
ulong padding_58;
|
||||||
|
ulong padding_59;
|
||||||
|
ulong padding_60;
|
||||||
|
ulong padding_61;
|
||||||
|
ulong padding_62;
|
||||||
|
ulong padding_63;
|
||||||
|
sampler sampler;
|
||||||
|
ulong padding_65;
|
||||||
|
ulong padding_66;
|
||||||
|
ulong padding_67;
|
||||||
|
ulong padding_68;
|
||||||
|
ulong padding_69;
|
||||||
|
ulong padding_70;
|
||||||
|
ulong padding_71;
|
||||||
|
ulong padding_72;
|
||||||
|
ulong padding_73;
|
||||||
|
ulong padding_74;
|
||||||
|
ulong padding_75;
|
||||||
|
ulong padding_76;
|
||||||
|
ulong padding_77;
|
||||||
|
ulong padding_78;
|
||||||
|
ulong padding_79;
|
||||||
|
ulong padding_80;
|
||||||
|
ulong padding_81;
|
||||||
|
ulong padding_82;
|
||||||
|
ulong padding_83;
|
||||||
|
ulong padding_84;
|
||||||
|
ulong padding_85;
|
||||||
|
ulong padding_86;
|
||||||
|
ulong padding_87;
|
||||||
|
ulong padding_88;
|
||||||
|
ulong padding_89;
|
||||||
|
ulong padding_90;
|
||||||
|
ulong padding_91;
|
||||||
|
ulong padding_92;
|
||||||
|
ulong padding_93;
|
||||||
|
ulong padding_94;
|
||||||
|
ulong padding_95;
|
||||||
|
ulong padding_96;
|
||||||
|
ulong padding_97;
|
||||||
|
ulong padding_98;
|
||||||
|
ulong padding_99;
|
||||||
|
ulong padding_100;
|
||||||
|
ulong padding_101;
|
||||||
|
ulong padding_102;
|
||||||
|
ulong padding_103;
|
||||||
|
ulong padding_104;
|
||||||
|
ulong padding_105;
|
||||||
|
ulong padding_106;
|
||||||
|
ulong padding_107;
|
||||||
|
ulong padding_108;
|
||||||
|
ulong padding_109;
|
||||||
|
ulong padding_110;
|
||||||
|
ulong padding_111;
|
||||||
|
ulong padding_112;
|
||||||
|
ulong padding_113;
|
||||||
|
ulong padding_114;
|
||||||
|
ulong padding_115;
|
||||||
|
ulong padding_116;
|
||||||
|
ulong padding_117;
|
||||||
|
ulong padding_118;
|
||||||
|
ulong padding_119;
|
||||||
|
ulong padding_120;
|
||||||
|
ulong padding_121;
|
||||||
|
ulong padding_122;
|
||||||
|
ulong padding_123;
|
||||||
|
ulong padding_124;
|
||||||
|
ulong padding_125;
|
||||||
|
ulong padding_126;
|
||||||
|
ulong padding_127;
|
||||||
|
};
|
||||||
|
|
||||||
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
||||||
const device float* texCoord [[buffer(0)]]) {
|
constant ConstantBuffers &constant_buffers [[buffer(20)]]) {
|
||||||
CopyVertexOut out;
|
CopyVertexOut out;
|
||||||
|
|
||||||
int low = vid & 1;
|
int low = vid & 1;
|
||||||
int high = vid >> 1;
|
int high = vid >> 1;
|
||||||
out.uv.x = texCoord[low];
|
out.uv.x = constant_buffers.texCoord->data[low];
|
||||||
out.uv.y = texCoord[2 + high];
|
out.uv.y = constant_buffers.texCoord->data[2 + high];
|
||||||
out.position.x = (float(low) - 0.5f) * 2.0f;
|
out.position.x = (float(low) - 0.5f) * 2.0f;
|
||||||
out.position.y = (float(high) - 0.5f) * 2.0f;
|
out.position.y = (float(high) - 0.5f) * 2.0f;
|
||||||
out.position.z = 0.0f;
|
out.position.z = 0.0f;
|
||||||
|
@ -24,7 +164,6 @@ vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment float4 fragmentMain(CopyVertexOut in [[stage_in]],
|
fragment float4 fragmentMain(CopyVertexOut in [[stage_in]],
|
||||||
texture2d<float, access::sample> texture [[texture(0)]],
|
constant Textures &textures [[buffer(22)]]) {
|
||||||
sampler sampler [[sampler(0)]]) {
|
return textures.texture.sample(textures.sampler, in.uv);
|
||||||
return texture.sample(sampler, in.uv);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,40 @@
|
||||||
|
|
||||||
using namespace metal;
|
using namespace metal;
|
||||||
|
|
||||||
kernel void kernelMain(constant int4& stride_arguments [[buffer(0)]],
|
struct StrideArguments {
|
||||||
device uint8_t* in_data [[buffer(1)]],
|
int4 data;
|
||||||
device uint8_t* out_data [[buffer(2)]],
|
};
|
||||||
|
|
||||||
|
struct InData {
|
||||||
|
uint8_t data[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OutData {
|
||||||
|
uint8_t data[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstantBuffers {
|
||||||
|
constant StrideArguments* stride_arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StorageBuffers {
|
||||||
|
ulong padding;
|
||||||
|
device InData* in_data;
|
||||||
|
device OutData* out_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(20)]],
|
||||||
|
device StorageBuffers &storage_buffers [[buffer(21)]],
|
||||||
uint3 thread_position_in_grid [[thread_position_in_grid]],
|
uint3 thread_position_in_grid [[thread_position_in_grid]],
|
||||||
uint3 threads_per_threadgroup [[threads_per_threadgroup]],
|
uint3 threads_per_threadgroup [[threads_per_threadgroup]],
|
||||||
uint3 threadgroups_per_grid [[threads_per_grid]])
|
uint3 threadgroups_per_grid [[threads_per_grid]])
|
||||||
{
|
{
|
||||||
// Determine what slice of the stride copies this invocation will perform.
|
// Determine what slice of the stride copies this invocation will perform.
|
||||||
|
|
||||||
int sourceStride = stride_arguments.x;
|
int sourceStride = constant_buffers.stride_arguments->data.x;
|
||||||
int targetStride = stride_arguments.y;
|
int targetStride = constant_buffers.stride_arguments->data.y;
|
||||||
int bufferSize = stride_arguments.z;
|
int bufferSize = constant_buffers.stride_arguments->data.z;
|
||||||
int sourceOffset = stride_arguments.w;
|
int sourceOffset = constant_buffers.stride_arguments->data.w;
|
||||||
|
|
||||||
int strideRemainder = targetStride - sourceStride;
|
int strideRemainder = targetStride - sourceStride;
|
||||||
int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
|
int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
|
||||||
|
@ -42,11 +63,11 @@ kernel void kernelMain(constant int4& stride_arguments [[buffer(0)]],
|
||||||
// Perform the copies for this region
|
// Perform the copies for this region
|
||||||
for (int i = 0; i < copyCount; i++) {
|
for (int i = 0; i < copyCount; i++) {
|
||||||
for (int j = 0; j < sourceStride; j++) {
|
for (int j = 0; j < sourceStride; j++) {
|
||||||
out_data[dstOffset++] = in_data[srcOffset++];
|
storage_buffers.out_data->data[dstOffset++] = storage_buffers.in_data->data[srcOffset++];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < strideRemainder; j++) {
|
for (int j = 0; j < strideRemainder; j++) {
|
||||||
out_data[dstOffset++] = uint8_t(0);
|
storage_buffers.out_data->data[dstOffset++] = uint8_t(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,14 @@ struct VertexOut {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ClearColor {
|
||||||
|
float4 data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstantBuffers {
|
||||||
|
constant ClearColor* clear_color;
|
||||||
|
};
|
||||||
|
|
||||||
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
||||||
int low = vid & 1;
|
int low = vid & 1;
|
||||||
int high = vid >> 1;
|
int high = vid >> 1;
|
||||||
|
@ -25,6 +33,6 @@ struct FragmentOut {
|
||||||
};
|
};
|
||||||
|
|
||||||
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
|
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
|
||||||
constant float4& clear_color [[buffer(0)]]) {
|
constant ConstantBuffers &constant_buffers [[buffer(20)]]) {
|
||||||
return {clear_color};
|
return {constant_buffers.clear_color->data};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,14 @@ struct FragmentOut {
|
||||||
uint stencil [[stencil]];
|
uint stencil [[stencil]];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ClearDepth {
|
||||||
|
float data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstantBuffers {
|
||||||
|
constant ClearDepth* clear_depth;
|
||||||
|
};
|
||||||
|
|
||||||
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
||||||
int low = vid & 1;
|
int low = vid & 1;
|
||||||
int high = vid >> 1;
|
int high = vid >> 1;
|
||||||
|
@ -26,10 +34,10 @@ vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
|
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
|
||||||
constant float& clear_depth [[buffer(0)]]) {
|
constant ConstantBuffers &constant_buffers [[buffer(20)]]) {
|
||||||
FragmentOut out;
|
FragmentOut out;
|
||||||
|
|
||||||
out.depth = clear_depth;
|
out.depth = constant_buffers.clear_depth->data;
|
||||||
// out.stencil = stencil_clear;
|
// out.stencil = stencil_clear;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
levels.length = (ulong)Info.Levels;
|
levels.length = (ulong)Info.Levels;
|
||||||
NSRange slices;
|
NSRange slices;
|
||||||
slices.location = (ulong)firstLayer;
|
slices.location = (ulong)firstLayer;
|
||||||
slices.length = (ulong)info.GetDepthOrLayers();
|
slices.length = textureType == MTLTextureType.Type3D ? 1 : (ulong)info.GetDepthOrLayers();
|
||||||
|
|
||||||
var swizzle = GetSwizzle(info, pixelFormat);
|
var swizzle = GetSwizzle(info, pixelFormat);
|
||||||
|
|
||||||
|
@ -287,14 +287,15 @@ namespace Ryujinx.Graphics.Metal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void SetData(IMemoryOwner<byte> data)
|
public void SetData(IMemoryOwner<byte> data)
|
||||||
{
|
{
|
||||||
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
|
var blitCommandEncoder = _pipeline.GetOrCreateBlitEncoder();
|
||||||
|
|
||||||
var dataSpan = data.Memory.Span;
|
var dataSpan = data.Memory.Span;
|
||||||
var mtlBuffer = _device.NewBuffer((ulong)dataSpan.Length, MTLResourceOptions.ResourceStorageModeShared);
|
|
||||||
var bufferSpan = new Span<byte>(mtlBuffer.Contents.ToPointer(), dataSpan.Length);
|
var buffer = _renderer.BufferManager.Create(dataSpan.Length);
|
||||||
dataSpan.CopyTo(bufferSpan);
|
buffer.SetDataUnchecked(0, dataSpan);
|
||||||
|
var mtlBuffer = buffer.GetBuffer(false).Get(_pipeline.Cbs).Value;
|
||||||
|
|
||||||
int width = Info.Width;
|
int width = Info.Width;
|
||||||
int height = Info.Height;
|
int height = Info.Height;
|
||||||
|
@ -342,7 +343,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
mtlBuffer.Dispose();
|
buffer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
public void SetData(IMemoryOwner<byte> data, int layer, int level)
|
||||||
|
@ -356,28 +357,26 @@ namespace Ryujinx.Graphics.Metal
|
||||||
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
var dataSpan = data.Memory.Span;
|
||||||
{
|
|
||||||
var dataSpan = data.Memory.Span;
|
|
||||||
var mtlBuffer = _device.NewBuffer((ulong)dataSpan.Length, MTLResourceOptions.ResourceStorageModeShared);
|
|
||||||
var bufferSpan = new Span<byte>(mtlBuffer.Contents.ToPointer(), dataSpan.Length);
|
|
||||||
dataSpan.CopyTo(bufferSpan);
|
|
||||||
|
|
||||||
blitCommandEncoder.CopyFromBuffer(
|
var buffer = _renderer.BufferManager.Create(dataSpan.Length);
|
||||||
mtlBuffer,
|
buffer.SetDataUnchecked(0, dataSpan);
|
||||||
0,
|
var mtlBuffer = buffer.GetBuffer(false).Get(_pipeline.Cbs).Value;
|
||||||
bytesPerRow,
|
|
||||||
bytesPerImage,
|
|
||||||
new MTLSize { width = _mtlTexture.Width, height = _mtlTexture.Height, depth = _mtlTexture.Depth },
|
|
||||||
_mtlTexture,
|
|
||||||
(ulong)layer,
|
|
||||||
(ulong)level,
|
|
||||||
new MTLOrigin()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Cleanup
|
blitCommandEncoder.CopyFromBuffer(
|
||||||
mtlBuffer.Dispose();
|
mtlBuffer,
|
||||||
}
|
0,
|
||||||
|
bytesPerRow,
|
||||||
|
bytesPerImage,
|
||||||
|
new MTLSize { width = _mtlTexture.Width, height = _mtlTexture.Height, depth = _mtlTexture.Depth },
|
||||||
|
_mtlTexture,
|
||||||
|
(ulong)layer,
|
||||||
|
(ulong)level,
|
||||||
|
new MTLOrigin()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
buffer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
|
||||||
|
@ -391,28 +390,26 @@ namespace Ryujinx.Graphics.Metal
|
||||||
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
bytesPerImage = bytesPerRow * (ulong)Info.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe
|
var dataSpan = data.Memory.Span;
|
||||||
{
|
|
||||||
var dataSpan = data.Memory.Span;
|
|
||||||
var mtlBuffer = _device.NewBuffer((ulong)dataSpan.Length, MTLResourceOptions.ResourceStorageModeShared);
|
|
||||||
var bufferSpan = new Span<byte>(mtlBuffer.Contents.ToPointer(), dataSpan.Length);
|
|
||||||
dataSpan.CopyTo(bufferSpan);
|
|
||||||
|
|
||||||
blitCommandEncoder.CopyFromBuffer(
|
var buffer = _renderer.BufferManager.Create(dataSpan.Length);
|
||||||
mtlBuffer,
|
buffer.SetDataUnchecked(0, dataSpan);
|
||||||
0,
|
var mtlBuffer = buffer.GetBuffer(false).Get(_pipeline.Cbs).Value;
|
||||||
bytesPerRow,
|
|
||||||
bytesPerImage,
|
|
||||||
new MTLSize { width = (ulong)region.Width, height = (ulong)region.Height, depth = 1 },
|
|
||||||
_mtlTexture,
|
|
||||||
(ulong)layer,
|
|
||||||
(ulong)level,
|
|
||||||
new MTLOrigin { x = (ulong)region.X, y = (ulong)region.Y }
|
|
||||||
);
|
|
||||||
|
|
||||||
// Cleanup
|
blitCommandEncoder.CopyFromBuffer(
|
||||||
mtlBuffer.Dispose();
|
mtlBuffer,
|
||||||
}
|
0,
|
||||||
|
bytesPerRow,
|
||||||
|
bytesPerImage,
|
||||||
|
new MTLSize { width = (ulong)region.Width, height = (ulong)region.Height, depth = 1 },
|
||||||
|
_mtlTexture,
|
||||||
|
(ulong)layer,
|
||||||
|
(ulong)level,
|
||||||
|
new MTLOrigin { x = (ulong)region.X, y = (ulong)region.Y }
|
||||||
|
);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
buffer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStorage(BufferRange buffer)
|
public void SetStorage(BufferRange buffer)
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
public const string Tab = " ";
|
public const string Tab = " ";
|
||||||
|
|
||||||
// The number of additional arguments that every function (except for the main one) must have (for instance support_buffer)
|
// The number of additional arguments that every function (except for the main one) must have (for instance support_buffer)
|
||||||
public const int AdditionalArgCount = 1;
|
public const int AdditionalArgCount = 2;
|
||||||
|
|
||||||
public StructuredFunction CurrentFunction { get; set; }
|
public StructuredFunction CurrentFunction { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
DeclareOutputAttributes(context, info.IoDefinitions.Where(x => x.StorageKind == StorageKind.Output));
|
DeclareOutputAttributes(context, info.IoDefinitions.Where(x => x.StorageKind == StorageKind.Output));
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values);
|
DeclareBufferStructures(context, context.Properties.ConstantBuffers.Values, true);
|
||||||
DeclareBufferStructures(context, context.Properties.StorageBuffers.Values);
|
DeclareBufferStructures(context, context.Properties.StorageBuffers.Values, false);
|
||||||
|
DeclareTextures(context, context.Properties.Textures.Values);
|
||||||
|
|
||||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.FindLSB) != 0)
|
if ((info.HelperFunctionsMask & HelperFunctionsMask.FindLSB) != 0)
|
||||||
{
|
{
|
||||||
|
@ -112,11 +113,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
{
|
{
|
||||||
string name = context.OperandManager.DeclareLocal(decl);
|
string name = context.OperandManager.DeclareLocal(decl);
|
||||||
|
|
||||||
context.AppendLine(GetVarTypeName(context, decl.VarType) + " " + name + ";");
|
context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetVarTypeName(CodeGenContext context, AggregateType type, bool atomic = false)
|
public static string GetVarTypeName(AggregateType type, bool atomic = false)
|
||||||
{
|
{
|
||||||
var s32 = atomic ? "atomic_int" : "int";
|
var s32 = atomic ? "atomic_int" : "int";
|
||||||
var u32 = atomic ? "atomic_uint" : "uint";
|
var u32 = atomic ? "atomic_uint" : "uint";
|
||||||
|
@ -155,21 +156,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
{
|
{
|
||||||
arraySize = $"[{memory.ArrayLength}]";
|
arraySize = $"[{memory.ArrayLength}]";
|
||||||
}
|
}
|
||||||
var typeName = GetVarTypeName(context, memory.Type & ~AggregateType.Array);
|
var typeName = GetVarTypeName(memory.Type & ~AggregateType.Array);
|
||||||
context.AppendLine($"{prefix}{typeName} {memory.Name}{arraySize};");
|
context.AppendLine($"{prefix}{typeName} {memory.Name}{arraySize};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareBufferStructures(CodeGenContext context, IEnumerable<BufferDefinition> buffers)
|
private static void DeclareBufferStructures(CodeGenContext context, IEnumerable<BufferDefinition> buffers, bool constant)
|
||||||
{
|
{
|
||||||
|
var name = constant ? "ConstantBuffers" : "StorageBuffers";
|
||||||
|
var count = constant ? Defaults.MaxUniformBuffersPerStage : Defaults.MaxStorageBuffersPerStage;
|
||||||
|
var addressSpace = constant ? "constant" : "device";
|
||||||
|
|
||||||
|
var argBufferPointers = new string[count];
|
||||||
|
|
||||||
foreach (BufferDefinition buffer in buffers)
|
foreach (BufferDefinition buffer in buffers)
|
||||||
{
|
{
|
||||||
context.AppendLine($"struct {DefaultNames.StructPrefix}_{buffer.Name}");
|
var needsPadding = buffer.Layout == BufferLayout.Std140;
|
||||||
|
|
||||||
|
argBufferPointers[buffer.Binding] = $"{addressSpace} {Defaults.StructPrefix}_{buffer.Name}* {buffer.Name};";
|
||||||
|
|
||||||
|
context.AppendLine($"struct {Defaults.StructPrefix}_{buffer.Name}");
|
||||||
context.EnterScope();
|
context.EnterScope();
|
||||||
|
|
||||||
foreach (StructureField field in buffer.Type.Fields)
|
foreach (StructureField field in buffer.Type.Fields)
|
||||||
{
|
{
|
||||||
string typeName = GetVarTypeName(context, field.Type & ~AggregateType.Array);
|
var type = field.Type;
|
||||||
|
type |= (needsPadding && (field.Type & AggregateType.Array) != 0) ? AggregateType.Vector4 : AggregateType.Invalid;
|
||||||
|
|
||||||
|
type &= ~AggregateType.Array;
|
||||||
|
|
||||||
|
string typeName = GetVarTypeName(type);
|
||||||
string arraySuffix = "";
|
string arraySuffix = "";
|
||||||
|
|
||||||
if (field.Type.HasFlag(AggregateType.Array))
|
if (field.Type.HasFlag(AggregateType.Array))
|
||||||
|
@ -191,6 +207,62 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
context.LeaveScope(";");
|
context.LeaveScope(";");
|
||||||
context.AppendLine();
|
context.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.AppendLine($"struct {name}");
|
||||||
|
context.EnterScope();
|
||||||
|
|
||||||
|
for (int i = 0; i < argBufferPointers.Length; i++)
|
||||||
|
{
|
||||||
|
if (argBufferPointers[i] == null)
|
||||||
|
{
|
||||||
|
// We need to pad the struct definition in order to read
|
||||||
|
// non-contiguous resources correctly.
|
||||||
|
context.AppendLine($"ulong padding_{i};");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.AppendLine(argBufferPointers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.LeaveScope(";");
|
||||||
|
context.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DeclareTextures(CodeGenContext context, IEnumerable<TextureDefinition> textures)
|
||||||
|
{
|
||||||
|
context.AppendLine("struct Textures");
|
||||||
|
context.EnterScope();
|
||||||
|
|
||||||
|
var argBufferPointers = new string[Defaults.MaxTexturesPerStage * 2];
|
||||||
|
|
||||||
|
foreach (TextureDefinition texture in textures)
|
||||||
|
{
|
||||||
|
var textureTypeName = texture.Type.ToMslTextureType();
|
||||||
|
argBufferPointers[texture.Binding] = $"{textureTypeName} tex_{texture.Name};";
|
||||||
|
|
||||||
|
if (!texture.Separate)
|
||||||
|
{
|
||||||
|
argBufferPointers[Defaults.MaxTexturesPerStage + texture.Binding] = $"sampler samp_{texture.Name};";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < argBufferPointers.Length; i++)
|
||||||
|
{
|
||||||
|
if (argBufferPointers[i] == null)
|
||||||
|
{
|
||||||
|
// We need to pad the struct definition in order to read
|
||||||
|
// non-contiguous resources correctly.
|
||||||
|
context.AppendLine($"ulong padding_{i};");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.AppendLine(argBufferPointers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.LeaveScope(";");
|
||||||
|
context.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs)
|
private static void DeclareInputAttributes(CodeGenContext context, IEnumerable<IoDefinition> inputs)
|
||||||
|
@ -201,7 +273,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (inputs.Any() || context.Definitions.Stage == ShaderStage.Fragment)
|
if (inputs.Any() || context.Definitions.Stage != ShaderStage.Compute)
|
||||||
{
|
{
|
||||||
string prefix = "";
|
string prefix = "";
|
||||||
|
|
||||||
|
@ -220,7 +292,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
if (context.Definitions.Stage == ShaderStage.Fragment)
|
if (context.Definitions.Stage == ShaderStage.Fragment)
|
||||||
{
|
{
|
||||||
// TODO: check if it's needed
|
// TODO: check if it's needed
|
||||||
context.AppendLine("float4 position [[position]];");
|
context.AppendLine("float4 position [[position, invariant]];");
|
||||||
context.AppendLine("bool front_facing [[front_facing]];");
|
context.AppendLine("bool front_facing [[front_facing]];");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +305,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
IoVariable.VertexId => "uint",
|
IoVariable.VertexId => "uint",
|
||||||
IoVariable.VertexIndex => "uint",
|
IoVariable.VertexIndex => "uint",
|
||||||
IoVariable.PointCoord => "float2",
|
IoVariable.PointCoord => "float2",
|
||||||
_ => GetVarTypeName(context, context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: false))
|
_ => GetVarTypeName(context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: false))
|
||||||
};
|
};
|
||||||
string name = ioDefinition.IoVariable switch
|
string name = ioDefinition.IoVariable switch
|
||||||
{
|
{
|
||||||
|
@ -242,11 +314,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
IoVariable.VertexId => "vertex_id",
|
IoVariable.VertexId => "vertex_id",
|
||||||
IoVariable.VertexIndex => "vertex_index",
|
IoVariable.VertexIndex => "vertex_index",
|
||||||
IoVariable.PointCoord => "point_coord",
|
IoVariable.PointCoord => "point_coord",
|
||||||
_ => $"{DefaultNames.IAttributePrefix}{ioDefinition.Location}"
|
_ => $"{Defaults.IAttributePrefix}{ioDefinition.Location}"
|
||||||
};
|
};
|
||||||
string suffix = ioDefinition.IoVariable switch
|
string suffix = ioDefinition.IoVariable switch
|
||||||
{
|
{
|
||||||
// IoVariable.Position => "[[position]]",
|
// IoVariable.Position => "[[position, invariant]]",
|
||||||
IoVariable.GlobalId => "[[thread_position_in_grid]]",
|
IoVariable.GlobalId => "[[thread_position_in_grid]]",
|
||||||
IoVariable.VertexId => "[[vertex_id]]",
|
IoVariable.VertexId => "[[vertex_id]]",
|
||||||
// TODO: Avoid potential redeclaration
|
// TODO: Avoid potential redeclaration
|
||||||
|
@ -297,9 +369,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
{
|
{
|
||||||
IoVariable.Position => "float4",
|
IoVariable.Position => "float4",
|
||||||
IoVariable.PointSize => "float",
|
IoVariable.PointSize => "float",
|
||||||
IoVariable.FragmentOutputColor => GetVarTypeName(context, context.Definitions.GetFragmentOutputColorType(ioDefinition.Location)),
|
IoVariable.FragmentOutputColor => GetVarTypeName(context.Definitions.GetFragmentOutputColorType(ioDefinition.Location)),
|
||||||
IoVariable.FragmentOutputDepth => "float",
|
IoVariable.FragmentOutputDepth => "float",
|
||||||
_ => GetVarTypeName(context, context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: true))
|
_ => GetVarTypeName(context.Definitions.GetUserDefinedType(ioDefinition.Location, isOutput: true))
|
||||||
};
|
};
|
||||||
string name = ioDefinition.IoVariable switch
|
string name = ioDefinition.IoVariable switch
|
||||||
{
|
{
|
||||||
|
@ -307,11 +379,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
IoVariable.PointSize => "point_size",
|
IoVariable.PointSize => "point_size",
|
||||||
IoVariable.FragmentOutputColor => $"color{ioDefinition.Location}",
|
IoVariable.FragmentOutputColor => $"color{ioDefinition.Location}",
|
||||||
IoVariable.FragmentOutputDepth => "depth",
|
IoVariable.FragmentOutputDepth => "depth",
|
||||||
_ => $"{DefaultNames.OAttributePrefix}{ioDefinition.Location}"
|
_ => $"{Defaults.OAttributePrefix}{ioDefinition.Location}"
|
||||||
};
|
};
|
||||||
string suffix = ioDefinition.IoVariable switch
|
string suffix = ioDefinition.IoVariable switch
|
||||||
{
|
{
|
||||||
IoVariable.Position => "[[position]]",
|
IoVariable.Position => "[[position, invariant]]",
|
||||||
IoVariable.PointSize => "[[point_size]]",
|
IoVariable.PointSize => "[[point_size]]",
|
||||||
IoVariable.UserDefined => $"[[user(loc{ioDefinition.Location})]]",
|
IoVariable.UserDefined => $"[[user(loc{ioDefinition.Location})]]",
|
||||||
IoVariable.FragmentOutputColor => $"[[color({ioDefinition.Location})]]",
|
IoVariable.FragmentOutputColor => $"[[color({ioDefinition.Location})]]",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
{
|
{
|
||||||
static class DefaultNames
|
static class Defaults
|
||||||
{
|
{
|
||||||
public const string LocalNamePrefix = "temp";
|
public const string LocalNamePrefix = "temp";
|
||||||
|
|
||||||
|
@ -13,5 +13,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
public const string ArgumentNamePrefix = "a";
|
public const string ArgumentNamePrefix = "a";
|
||||||
|
|
||||||
public const string UndefinedName = "0";
|
public const string UndefinedName = "0";
|
||||||
|
|
||||||
|
public const int MaxUniformBuffersPerStage = 18;
|
||||||
|
public const int MaxStorageBuffersPerStage = 16;
|
||||||
|
public const int MaxTexturesPerStage = 64;
|
||||||
|
|
||||||
|
public const uint ConstantBuffersIndex = 20;
|
||||||
|
public const uint StorageBuffersIndex = 21;
|
||||||
|
public const uint TexturesIndex = 22;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -49,8 +49,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
? AggregateType.S32
|
? AggregateType.S32
|
||||||
: AggregateType.U32;
|
: AggregateType.U32;
|
||||||
|
|
||||||
builder.Append($"(device {Declarations.GetVarTypeName(context, dstType, true)}*)&{GenerateLoadOrStore(context, operation, isStore: false)}");
|
builder.Append($"(device {Declarations.GetVarTypeName(dstType, true)}*)&{GenerateLoadOrStore(context, operation, isStore: false)}");
|
||||||
|
|
||||||
|
|
||||||
for (int argIndex = operation.SourcesCount - arity + 2; argIndex < operation.SourcesCount; argIndex++)
|
for (int argIndex = operation.SourcesCount - arity + 2; argIndex < operation.SourcesCount; argIndex++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,11 +21,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
if (context.Definitions.Stage != ShaderStage.Compute)
|
if (context.Definitions.Stage != ShaderStage.Compute)
|
||||||
{
|
{
|
||||||
args[0] = "in";
|
args[0] = "in";
|
||||||
args[1] = "support_buffer";
|
args[1] = "constant_buffers";
|
||||||
|
args[2] = "storage_buffers";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args[0] = "support_buffer";
|
args[0] = "constant_buffers";
|
||||||
|
args[1] = "storage_buffers";
|
||||||
}
|
}
|
||||||
|
|
||||||
int argIndex = additionalArgCount;
|
int argIndex = additionalArgCount;
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
int srcIndex = 0;
|
int srcIndex = 0;
|
||||||
bool isStoreOrAtomic = operation.Inst == Instruction.Store || operation.Inst.IsAtomic();
|
bool isStoreOrAtomic = operation.Inst == Instruction.Store || operation.Inst.IsAtomic();
|
||||||
int inputsCount = isStoreOrAtomic ? operation.SourcesCount - 1 : operation.SourcesCount;
|
int inputsCount = isStoreOrAtomic ? operation.SourcesCount - 1 : operation.SourcesCount;
|
||||||
|
bool fieldHasPadding = false;
|
||||||
|
|
||||||
if (operation.Inst == Instruction.AtomicCompareAndSwap)
|
if (operation.Inst == Instruction.AtomicCompareAndSwap)
|
||||||
{
|
{
|
||||||
|
@ -46,7 +47,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
StructureField field = buffer.Type.Fields[fieldIndex.Value];
|
StructureField field = buffer.Type.Fields[fieldIndex.Value];
|
||||||
varName = buffer.Name;
|
|
||||||
|
fieldHasPadding = buffer.Layout == BufferLayout.Std140
|
||||||
|
&& ((field.Type & AggregateType.Vector4) == 0)
|
||||||
|
&& ((field.Type & AggregateType.Array) != 0);
|
||||||
|
|
||||||
|
varName = storageKind == StorageKind.ConstantBuffer
|
||||||
|
? "constant_buffers"
|
||||||
|
: "storage_buffers";
|
||||||
|
varName += "." + buffer.Name;
|
||||||
varName += "->" + field.Name;
|
varName += "->" + field.Name;
|
||||||
varType = field.Type;
|
varType = field.Type;
|
||||||
break;
|
break;
|
||||||
|
@ -130,6 +139,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
varName += fieldName;
|
varName += fieldName;
|
||||||
|
varName += fieldHasPadding ? ".x" : "";
|
||||||
|
|
||||||
if (isStore)
|
if (isStore)
|
||||||
{
|
{
|
||||||
|
@ -173,7 +183,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
coordsExpr = GetSourceExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32);
|
coordsExpr = GetSourceExpr(context, texOp.GetSource(coordsIndex), AggregateType.FP32);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"tex_{samplerName}.calculate_unclamped_lod(samp_{samplerName}, {coordsExpr}){GetMaskMultiDest(texOp.Index)}";
|
return $"textures.tex_{samplerName}.calculate_unclamped_lod(textures.samp_{samplerName}, {coordsExpr}){GetMaskMultiDest(texOp.Index)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Store(CodeGenContext context, AstOperation operation)
|
public static string Store(CodeGenContext context, AstOperation operation)
|
||||||
|
@ -199,7 +209,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
bool colorIsVector = isGather || !isShadow;
|
bool colorIsVector = isGather || !isShadow;
|
||||||
|
|
||||||
string samplerName = GetSamplerName(context.Properties, texOp);
|
string samplerName = GetSamplerName(context.Properties, texOp);
|
||||||
string texCall = $"tex_{samplerName}";
|
string texCall = $"textures.tex_{samplerName}";
|
||||||
texCall += ".";
|
texCall += ".";
|
||||||
|
|
||||||
int srcIndex = 0;
|
int srcIndex = 0;
|
||||||
|
@ -229,7 +239,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
texCall += "_compare";
|
texCall += "_compare";
|
||||||
}
|
}
|
||||||
|
|
||||||
texCall += $"(samp_{samplerName}, ";
|
texCall += $"(textures.samp_{samplerName}, ";
|
||||||
}
|
}
|
||||||
|
|
||||||
int coordsCount = texOp.Type.GetDimensions();
|
int coordsCount = texOp.Type.GetDimensions();
|
||||||
|
@ -385,7 +395,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
string samplerName = GetSamplerName(context.Properties, texOp);
|
string samplerName = GetSamplerName(context.Properties, texOp);
|
||||||
string textureName = $"tex_{samplerName}";
|
string textureName = $"textures.tex_{samplerName}";
|
||||||
string texCall = textureName + ".";
|
string texCall = textureName + ".";
|
||||||
texCall += "get_num_samples()";
|
texCall += "get_num_samples()";
|
||||||
|
|
||||||
|
@ -397,7 +407,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||||
|
|
||||||
string samplerName = GetSamplerName(context.Properties, texOp);
|
string samplerName = GetSamplerName(context.Properties, texOp);
|
||||||
string textureName = $"tex_{samplerName}";
|
string textureName = $"textures.tex_{samplerName}";
|
||||||
string texCall = textureName + ".";
|
string texCall = textureName + ".";
|
||||||
|
|
||||||
if (texOp.Index == 3)
|
if (texOp.Index == 3)
|
||||||
|
|
|
@ -60,8 +60,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl.Instructions
|
||||||
private static (string, AggregateType) GetUserDefinedVariableName(ShaderDefinitions definitions, int location, int component, bool isOutput, bool isPerPatch)
|
private static (string, AggregateType) GetUserDefinedVariableName(ShaderDefinitions definitions, int location, int component, bool isOutput, bool isPerPatch)
|
||||||
{
|
{
|
||||||
string name = isPerPatch
|
string name = isPerPatch
|
||||||
? DefaultNames.PerPatchAttributePrefix
|
? Defaults.PerPatchAttributePrefix
|
||||||
: (isOutput ? DefaultNames.OAttributePrefix : DefaultNames.IAttributePrefix);
|
: (isOutput ? Defaults.OAttributePrefix : Defaults.IAttributePrefix);
|
||||||
|
|
||||||
if (location < 0)
|
if (location < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -73,18 +73,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
if (stage != ShaderStage.Compute)
|
if (stage != ShaderStage.Compute)
|
||||||
{
|
{
|
||||||
args[0] = stage == ShaderStage.Vertex ? "VertexIn in" : "FragmentIn in";
|
args[0] = stage == ShaderStage.Vertex ? "VertexIn in" : "FragmentIn in";
|
||||||
args[1] = $"constant {DefaultNames.StructPrefix}_support_buffer* support_buffer";
|
args[1] = "constant ConstantBuffers &constant_buffers";
|
||||||
|
args[2] = "device StorageBuffers &storage_buffers";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args[0] = $"constant {DefaultNames.StructPrefix}_support_buffer* support_buffer";
|
args[0] = "constant ConstantBuffers &constant_buffers";
|
||||||
|
args[1] = "device StorageBuffers &storage_buffers";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int argIndex = additionalArgCount;
|
int argIndex = additionalArgCount;
|
||||||
for (int i = 0; i < function.InArguments.Length; i++)
|
for (int i = 0; i < function.InArguments.Length; i++)
|
||||||
{
|
{
|
||||||
args[argIndex++] = $"{Declarations.GetVarTypeName(context, function.InArguments[i])} {OperandManager.GetArgumentName(i)}";
|
args[argIndex++] = $"{Declarations.GetVarTypeName(function.InArguments[i])} {OperandManager.GetArgumentName(i)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < function.OutArguments.Length; i++)
|
for (int i = 0; i < function.OutArguments.Length; i++)
|
||||||
|
@ -92,12 +94,12 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
int j = i + function.InArguments.Length;
|
int j = i + function.InArguments.Length;
|
||||||
|
|
||||||
// Likely need to be made into pointers
|
// Likely need to be made into pointers
|
||||||
args[argIndex++] = $"out {Declarations.GetVarTypeName(context, function.OutArguments[i])} {OperandManager.GetArgumentName(j)}";
|
args[argIndex++] = $"out {Declarations.GetVarTypeName(function.OutArguments[i])} {OperandManager.GetArgumentName(j)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
string funcKeyword = "inline";
|
string funcKeyword = "inline";
|
||||||
string funcName = null;
|
string funcName = null;
|
||||||
string returnType = Declarations.GetVarTypeName(context, function.ReturnType);
|
string returnType = Declarations.GetVarTypeName(function.ReturnType);
|
||||||
|
|
||||||
if (isMainFunc)
|
if (isMainFunc)
|
||||||
{
|
{
|
||||||
|
@ -122,10 +124,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
|
|
||||||
if (stage == ShaderStage.Vertex)
|
if (stage == ShaderStage.Vertex)
|
||||||
{
|
{
|
||||||
if (context.AttributeUsage.UsedInputAttributes != 0)
|
args = args.Prepend("VertexIn in [[stage_in]]").ToArray();
|
||||||
{
|
|
||||||
args = args.Prepend("VertexIn in [[stage_in]]").ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (stage == ShaderStage.Fragment)
|
else if (stage == ShaderStage.Fragment)
|
||||||
{
|
{
|
||||||
|
@ -148,27 +147,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
args = args.Append("uint thread_index_in_simdgroup [[thread_index_in_simdgroup]]").ToArray();
|
args = args.Append("uint thread_index_in_simdgroup [[thread_index_in_simdgroup]]").ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var constantBuffer in context.Properties.ConstantBuffers.Values)
|
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 {DefaultNames.StructPrefix}_{constantBuffer.Name}* {constantBuffer.Name} [[buffer({constantBuffer.Binding})]]").ToArray();
|
args = args.Append($"constant Textures &textures [[buffer({Defaults.TexturesIndex})]]").ToArray();
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var storageBuffers in context.Properties.StorageBuffers.Values)
|
|
||||||
{
|
|
||||||
// Offset the binding by 15 to avoid clashing with the constant buffers
|
|
||||||
args = args.Append($"device {DefaultNames.StructPrefix}_{storageBuffers.Name}* {storageBuffers.Name} [[buffer({storageBuffers.Binding + 15})]]").ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var texture in context.Properties.Textures.Values)
|
|
||||||
{
|
|
||||||
var textureTypeName = texture.Type.ToMslTextureType();
|
|
||||||
args = args.Append($"{textureTypeName} tex_{texture.Name} [[texture({texture.Binding})]]").ToArray();
|
|
||||||
// If the texture is not separate, we need to declare a sampler
|
|
||||||
if (!texture.Separate)
|
|
||||||
{
|
|
||||||
args = args.Append($"sampler samp_{texture.Name} [[sampler({texture.Binding})]]").ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var funcPrefix = $"{funcKeyword} {returnType} {funcName ?? function.Name}(";
|
var funcPrefix = $"{funcKeyword} {returnType} {funcName ?? function.Name}(";
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
|
|
||||||
public string DeclareLocal(AstOperand operand)
|
public string DeclareLocal(AstOperand operand)
|
||||||
{
|
{
|
||||||
string name = $"{DefaultNames.LocalNamePrefix}_{_locals.Count}";
|
string name = $"{Defaults.LocalNamePrefix}_{_locals.Count}";
|
||||||
|
|
||||||
_locals.Add(operand, name);
|
_locals.Add(operand, name);
|
||||||
|
|
||||||
|
@ -34,14 +34,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
|
||||||
OperandType.Argument => GetArgumentName(operand.Value),
|
OperandType.Argument => GetArgumentName(operand.Value),
|
||||||
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
|
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
|
||||||
OperandType.LocalVariable => _locals[operand],
|
OperandType.LocalVariable => _locals[operand],
|
||||||
OperandType.Undefined => DefaultNames.UndefinedName,
|
OperandType.Undefined => Defaults.UndefinedName,
|
||||||
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\"."),
|
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\"."),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetArgumentName(int argIndex)
|
public static string GetArgumentName(int argIndex)
|
||||||
{
|
{
|
||||||
return $"{DefaultNames.ArgumentNamePrefix}{argIndex}";
|
return $"{Defaults.ArgumentNamePrefix}{argIndex}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AggregateType GetNodeDestType(CodeGenContext context, IAstNode node)
|
public static AggregateType GetNodeDestType(CodeGenContext context, IAstNode node)
|
||||||
|
|
Loading…
Reference in a new issue