mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-12-18 18:12:00 +00:00
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 ShaderStage Stage;
|
||||||
public TextureBase Storage;
|
public TextureBase Storage;
|
||||||
public Sampler Sampler;
|
public Sampler Sampler;
|
||||||
|
public Format ImageFormat;
|
||||||
|
|
||||||
public TextureRef(ShaderStage stage, TextureBase storage, Sampler sampler)
|
public TextureRef(ShaderStage stage, TextureBase storage, Sampler sampler)
|
||||||
{
|
{
|
||||||
|
@ -101,11 +102,19 @@ namespace Ryujinx.Graphics.Metal
|
||||||
public PipelineState Pipeline;
|
public PipelineState Pipeline;
|
||||||
public DepthStencilUid DepthStencilUid;
|
public DepthStencilUid DepthStencilUid;
|
||||||
|
|
||||||
|
public readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
|
||||||
|
|
||||||
public readonly BufferRef[] UniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings];
|
public readonly BufferRef[] UniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings];
|
||||||
public readonly BufferRef[] StorageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings];
|
public readonly BufferRef[] StorageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings];
|
||||||
public readonly TextureRef[] TextureRefs = new TextureRef[Constants.MaxTextureBindings];
|
public readonly TextureRef[] TextureRefs = new TextureRef[Constants.MaxTextureBindings];
|
||||||
public readonly ImageRef[] ImageRefs = new ImageRef[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 IndexBufferState IndexBuffer = default;
|
||||||
|
|
||||||
public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip;
|
public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip;
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace Ryujinx.Graphics.Metal
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
struct EncoderStateManager : IDisposable
|
struct EncoderStateManager : IDisposable
|
||||||
{
|
{
|
||||||
|
private const int ArrayGrowthSize = 16;
|
||||||
|
|
||||||
private readonly MTLDevice _device;
|
private readonly MTLDevice _device;
|
||||||
private readonly Pipeline _pipeline;
|
private readonly Pipeline _pipeline;
|
||||||
private readonly BufferManager _bufferManager;
|
private readonly BufferManager _bufferManager;
|
||||||
|
@ -90,6 +92,16 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_currentState.ClearLoadAction = clear;
|
_currentState.ClearLoadAction = clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DirtyTextures()
|
||||||
|
{
|
||||||
|
_currentState.Dirty |= DirtyFlags.Textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DirtyImages()
|
||||||
|
{
|
||||||
|
_currentState.Dirty |= DirtyFlags.Images;
|
||||||
|
}
|
||||||
|
|
||||||
public readonly MTLRenderCommandEncoder CreateRenderCommandEncoder()
|
public readonly MTLRenderCommandEncoder CreateRenderCommandEncoder()
|
||||||
{
|
{
|
||||||
// Initialise Pass & State
|
// Initialise Pass & State
|
||||||
|
@ -831,6 +843,66 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_currentState.Dirty |= DirtyFlags.Images;
|
_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)
|
private readonly void SetDepthStencilState(MTLRenderCommandEncoder renderCommandEncoder)
|
||||||
{
|
{
|
||||||
MTLDepthStencilState state = _depthStencilCache.GetOrCreate(_currentState.DepthStencilUid);
|
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.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using SharpMetal.Metal;
|
using SharpMetal.Metal;
|
||||||
|
@ -97,7 +96,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public IImageArray CreateImageArray(int size, bool isBuffer)
|
public IImageArray CreateImageArray(int size, bool isBuffer)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return new ImageArray(size, isBuffer, _pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
|
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
|
||||||
|
@ -122,7 +121,7 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public ITextureArray CreateTextureArray(int size, bool isBuffer)
|
public ITextureArray CreateTextureArray(int size, bool isBuffer)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return new TextureArray(size, isBuffer, _pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool PrepareHostMapping(IntPtr address, ulong size)
|
public bool PrepareHostMapping(IntPtr address, ulong size)
|
||||||
|
|
|
@ -192,6 +192,16 @@ namespace Ryujinx.Graphics.Metal
|
||||||
_renderer.RegisterFlush();
|
_renderer.RegisterFlush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DirtyTextures()
|
||||||
|
{
|
||||||
|
_encoderStateManager.DirtyTextures();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DirtyImages()
|
||||||
|
{
|
||||||
|
_encoderStateManager.DirtyImages();
|
||||||
|
}
|
||||||
|
|
||||||
public void Blit(
|
public void Blit(
|
||||||
Texture src,
|
Texture src,
|
||||||
Texture dst,
|
Texture dst,
|
||||||
|
@ -542,12 +552,20 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
|
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)
|
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)
|
public void SetLineParameters(float width, bool smooth)
|
||||||
|
@ -656,12 +674,20 @@ namespace Ryujinx.Graphics.Metal
|
||||||
|
|
||||||
public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
|
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)
|
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)
|
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