TextureArray & ImageArray Creation + State
This commit is contained in:
parent
d07f6ed38e
commit
47b99e6bc3
6 changed files with 270 additions and 7 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
74
src/Ryujinx.Graphics.Metal/ImageArray.cs
Normal file
74
src/Ryujinx.Graphics.Metal/ImageArray.cs
Normal 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() { }
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
83
src/Ryujinx.Graphics.Metal/TextureArray.cs
Normal file
83
src/Ryujinx.Graphics.Metal/TextureArray.cs
Normal 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() { }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue