Metal: Compute Shaders (#19)

* check for too bix texture bindings

* implement lod query

* print shader stage name

* always have fragment input

* resolve merge conflicts

* fix: lod query

* fix: casting texture coords

* support non-array memories

* use structure types for buffers

* implement compute pipeline cache

* compute dispatch

* improve error message

* rebind compute state

* bind compute textures

* pass local size as an argument to dispatch

* implement texture buffers

* hack: change vertex index to vertex id

* pass support buffer as an argument to every function

* return at the end of function

* fix: certain missing compute bindings

* implement texture base

* improve texture binding system

* remove useless exception

* move texture handle to texture base

* fix: segfault when using disposed textures

---------

Co-authored-by: Samuliak <samuliak77@gmail.com>
Co-authored-by: SamoZ256 <96914946+SamoZ256@users.noreply.github.com>
This commit is contained in:
Isaac Marovitz 2024-05-29 16:21:59 +01:00
parent 131ab75d55
commit b064d76a4f
26 changed files with 718 additions and 224 deletions

View file

@ -69,7 +69,6 @@ namespace Ryujinx.Graphics.Metal
public MTLRenderCommandEncoder GetOrCreateRenderEncoder()
{
MTLRenderCommandEncoder renderCommandEncoder;
if (_currentEncoder == null || _currentEncoderType != EncoderType.Render)
{
renderCommandEncoder = BeginRenderPass();
@ -79,7 +78,7 @@ namespace Ryujinx.Graphics.Metal
renderCommandEncoder = new MTLRenderCommandEncoder(_currentEncoder.Value);
}
_encoderStateManager.RebindState(renderCommandEncoder);
_encoderStateManager.RebindRenderState(renderCommandEncoder);
return renderCommandEncoder;
}
@ -99,15 +98,19 @@ namespace Ryujinx.Graphics.Metal
public MTLComputeCommandEncoder GetOrCreateComputeEncoder()
{
if (_currentEncoder != null)
MTLComputeCommandEncoder computeCommandEncoder;
if (_currentEncoder == null || _currentEncoderType != EncoderType.Compute)
{
if (_currentEncoderType == EncoderType.Compute)
{
return new MTLComputeCommandEncoder(_currentEncoder.Value);
}
computeCommandEncoder = BeginComputePass();
}
else
{
computeCommandEncoder = new MTLComputeCommandEncoder(_currentEncoder.Value);
}
return BeginComputePass();
_encoderStateManager.RebindComputeState(computeCommandEncoder);
return computeCommandEncoder;
}
public void EndCurrentPass()
@ -164,8 +167,7 @@ namespace Ryujinx.Graphics.Metal
{
EndCurrentPass();
var descriptor = new MTLComputePassDescriptor();
var computeCommandEncoder = _commandBuffer.ComputeCommandEncoder(descriptor);
var computeCommandEncoder = _encoderStateManager.CreateComputeCommandEncoder();
_currentEncoder = computeCommandEncoder;
_currentEncoderType = EncoderType.Compute;
@ -274,9 +276,13 @@ namespace Ryujinx.Graphics.Metal
(ulong)size);
}
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
var computeCommandEncoder = GetOrCreateComputeEncoder();
computeCommandEncoder.DispatchThreadgroups(
new MTLSize{width = (ulong)groupsX, height = (ulong)groupsY, depth = (ulong)groupsZ},
new MTLSize{width = (ulong)groupSizeX, height = (ulong)groupSizeY, depth = (ulong)groupSizeZ});
}
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
@ -397,7 +403,10 @@ namespace Ryujinx.Graphics.Metal
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
if (texture is TextureBase tex)
{
_encoderStateManager.UpdateTexture(stage, (ulong)binding, tex);
}
}
public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
@ -491,28 +500,14 @@ namespace Ryujinx.Graphics.Metal
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
if (texture is Texture tex)
if (texture is TextureBase tex)
{
if (sampler is Sampler samp)
{
var mtlTexture = tex.MTLTexture;
var mtlSampler = samp.GetSampler();
var index = (ulong)binding;
switch (stage)
{
case ShaderStage.Vertex:
case ShaderStage.Fragment:
_encoderStateManager.UpdateTextureAndSampler(stage, index, mtlTexture, mtlSampler);
break;
case ShaderStage.Compute:
var computeCommandEncoder = GetOrCreateComputeEncoder();
computeCommandEncoder.SetTexture(mtlTexture, index);
computeCommandEncoder.SetSamplerState(mtlSampler, index);
break;
default:
throw new ArgumentOutOfRangeException(nameof(stage), stage, "Unsupported shader stage!");
}
_encoderStateManager.UpdateTextureAndSampler(stage, index, tex, mtlSampler);
}
}
}