TextureArray & ImageArray Creation + State

This commit is contained in:
Isaac Marovitz 2024-07-31 16:29:48 +01:00 committed by Isaac Marovitz
parent d07f6ed38e
commit 47b99e6bc3
6 changed files with 270 additions and 7 deletions

View file

@ -56,6 +56,7 @@ namespace Ryujinx.Graphics.Metal
public ShaderStage Stage;
public TextureBase Storage;
public Sampler Sampler;
public Format ImageFormat;
public TextureRef(ShaderStage stage, TextureBase storage, Sampler sampler)
{
@ -101,11 +102,19 @@ namespace Ryujinx.Graphics.Metal
public PipelineState Pipeline;
public DepthStencilUid DepthStencilUid;
public readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
public readonly BufferRef[] UniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings];
public readonly BufferRef[] StorageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings];
public readonly TextureRef[] TextureRefs = new TextureRef[Constants.MaxTextureBindings];
public readonly ImageRef[] ImageRefs = new ImageRef[Constants.MaxTextureBindings];
public ArrayRef<TextureArray>[] TextureArrayRefs = [];
public ArrayRef<ImageArray>[] ImageArrayRefs = [];
public ArrayRef<TextureArray>[] TextureArrayExtraRefs = [];
public ArrayRef<ImageArray>[] ImageArrayExtraRefs = [];
public IndexBufferState IndexBuffer = default;
public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip;

View file

@ -14,6 +14,8 @@ namespace Ryujinx.Graphics.Metal
[SupportedOSPlatform("macos")]
struct EncoderStateManager : IDisposable
{
private const int ArrayGrowthSize = 16;
private readonly MTLDevice _device;
private readonly Pipeline _pipeline;
private readonly BufferManager _bufferManager;
@ -90,6 +92,16 @@ namespace Ryujinx.Graphics.Metal
_currentState.ClearLoadAction = clear;
}
public void DirtyTextures()
{
_currentState.Dirty |= DirtyFlags.Textures;
}
public void DirtyImages()
{
_currentState.Dirty |= DirtyFlags.Images;
}
public readonly MTLRenderCommandEncoder CreateRenderCommandEncoder()
{
// Initialise Pass & State
@ -831,6 +843,66 @@ namespace Ryujinx.Graphics.Metal
_currentState.Dirty |= DirtyFlags.Images;
}
public void UpdateTextureArray(ShaderStage stage, ulong binding, TextureArray array)
{
ref EncoderState.ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _currentState.TextureArrayRefs, (int)binding, ArrayGrowthSize);
if (arrayRef.Stage != stage || arrayRef.Array != array)
{
arrayRef = new EncoderState.ArrayRef<TextureArray>(stage, array);
_currentState.Dirty |= DirtyFlags.Textures;
}
}
public void UpdateTextureArraySeparate(ShaderStage stage, int setIndex, TextureArray array)
{
ref EncoderState.ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _currentState.TextureArrayRefs, setIndex);
if (arrayRef.Stage != stage || arrayRef.Array != array)
{
arrayRef = new EncoderState.ArrayRef<TextureArray>(stage, array);
_currentState.Dirty |= DirtyFlags.Textures;
}
}
public void UpdateImageArray(ShaderStage stage, ulong binding, ImageArray array)
{
ref EncoderState.ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _currentState.ImageArrayRefs, (int)binding, ArrayGrowthSize);
if (arrayRef.Stage != stage || arrayRef.Array != array)
{
arrayRef = new EncoderState.ArrayRef<ImageArray>(stage, array);
_currentState.Dirty |= DirtyFlags.Images;
}
}
public void UpdateImageArraySeparate(ShaderStage stage, int setIndex, ImageArray array)
{
ref EncoderState.ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _currentState.ImageArrayExtraRefs, setIndex);
if (arrayRef.Stage != stage || arrayRef.Array != array)
{
arrayRef = new EncoderState.ArrayRef<ImageArray>(stage, array);
_currentState.Dirty |= DirtyFlags.Images;
}
}
private static ref EncoderState.ArrayRef<T> GetArrayRef<T>(ref EncoderState.ArrayRef<T>[] array, int index, int growthSize = 1)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
if (array.Length <= index)
{
Array.Resize(ref array, index + growthSize);
}
return ref array[index];
}
private readonly void SetDepthStencilState(MTLRenderCommandEncoder renderCommandEncoder)
{
MTLDepthStencilState state = _depthStencilCache.GetOrCreate(_currentState.DepthStencilUid);

View file

@ -0,0 +1,74 @@
using Ryujinx.Graphics.GAL;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
internal class ImageArray : IImageArray
{
private readonly TextureRef[] _textureRefs;
private readonly TextureBuffer[] _bufferTextureRefs;
private readonly bool _isBuffer;
private readonly Pipeline _pipeline;
public ImageArray(int size, bool isBuffer, Pipeline pipeline)
{
if (isBuffer)
{
_bufferTextureRefs = new TextureBuffer[size];
}
else
{
_textureRefs = new TextureRef[size];
}
_isBuffer = isBuffer;
_pipeline = pipeline;
}
public void SetFormats(int index, Format[] imageFormats)
{
for (int i = 0; i < imageFormats.Length; i++)
{
_textureRefs[index + i].ImageFormat = imageFormats[i];
}
SetDirty();
}
public void SetImages(int index, ITexture[] images)
{
for (int i = 0; i < images.Length; i++)
{
ITexture image = images[i];
if (image is TextureBuffer textureBuffer)
{
_bufferTextureRefs[index + i] = textureBuffer;
}
else if (image is Texture texture)
{
_textureRefs[index + i].Storage = texture;
}
else if (!_isBuffer)
{
_textureRefs[index + i].Storage = null;
}
else
{
_bufferTextureRefs[index + i] = null;
}
}
SetDirty();
}
private void SetDirty()
{
_pipeline.DirtyImages();
}
public void Dispose() { }
}
}

View file

@ -1,5 +1,4 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader.Translation;
using SharpMetal.Metal;
@ -97,7 +96,7 @@ namespace Ryujinx.Graphics.Metal
public IImageArray CreateImageArray(int size, bool isBuffer)
{
throw new NotImplementedException();
return new ImageArray(size, isBuffer, _pipeline);
}
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
@ -122,7 +121,7 @@ namespace Ryujinx.Graphics.Metal
public ITextureArray CreateTextureArray(int size, bool isBuffer)
{
throw new NotImplementedException();
return new TextureArray(size, isBuffer, _pipeline);
}
public bool PrepareHostMapping(IntPtr address, ulong size)

View file

@ -192,6 +192,16 @@ namespace Ryujinx.Graphics.Metal
_renderer.RegisterFlush();
}
public void DirtyTextures()
{
_encoderStateManager.DirtyTextures();
}
public void DirtyImages()
{
_encoderStateManager.DirtyImages();
}
public void Blit(
Texture src,
Texture dst,
@ -542,12 +552,20 @@ namespace Ryujinx.Graphics.Metal
public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
if (array is ImageArray imageArray)
{
var index = (ulong)binding;
_encoderStateManager.UpdateImageArray(stage, index, imageArray);
}
}
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
if (array is ImageArray imageArray)
{
_encoderStateManager.UpdateImageArraySeparate(stage, setIndex, imageArray);
}
}
public void SetLineParameters(float width, bool smooth)
@ -656,12 +674,20 @@ namespace Ryujinx.Graphics.Metal
public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
if (array is TextureArray textureArray)
{
var index = (ulong)binding;
_encoderStateManager.UpdateTextureArray(stage, index, textureArray);
}
}
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
if (array is TextureArray textureArray)
{
_encoderStateManager.UpdateTextureArraySeparate(stage, setIndex, textureArray);
}
}
public void SetUserClipDistance(int index, bool enableClip)

View file

@ -0,0 +1,83 @@
using Ryujinx.Graphics.GAL;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
internal class TextureArray : ITextureArray
{
private readonly TextureRef[] _textureRefs;
private readonly TextureBuffer[] _bufferTextureRefs;
private readonly bool _isBuffer;
private readonly Pipeline _pipeline;
public TextureArray(int size, bool isBuffer, Pipeline pipeline)
{
if (isBuffer)
{
_bufferTextureRefs = new TextureBuffer[size];
}
else
{
_textureRefs = new TextureRef[size];
}
_isBuffer = isBuffer;
_pipeline = pipeline;
}
public void SetSamplers(int index, ISampler[] samplers)
{
for (int i = 0; i < samplers.Length; i++)
{
ISampler sampler = samplers[i];
if (sampler is Sampler samp)
{
_textureRefs[index + i].Sampler = samp;
}
else
{
_textureRefs[index + i].Sampler = default;
}
}
SetDirty();
}
public void SetTextures(int index, ITexture[] textures)
{
for (int i = 0; i < textures.Length; i++)
{
ITexture texture = textures[i];
if (texture is TextureBuffer textureBuffer)
{
_bufferTextureRefs[index + i] = textureBuffer;
}
else if (texture is Texture tex)
{
_textureRefs[index + i].Storage = tex;
}
else if (!_isBuffer)
{
_textureRefs[index + i].Storage = null;
}
else
{
_bufferTextureRefs[index + i] = null;
}
}
SetDirty();
}
private void SetDirty()
{
_pipeline.DirtyTextures();
}
public void Dispose() { }
}
}