diff --git a/src/Ryujinx.Graphics.GAL/ComputeSize.cs b/src/Ryujinx.Graphics.GAL/ComputeSize.cs
new file mode 100644
index 0000000000..ce9c2531c8
--- /dev/null
+++ b/src/Ryujinx.Graphics.GAL/ComputeSize.cs
@@ -0,0 +1,18 @@
+namespace Ryujinx.Graphics.GAL
+{
+ public readonly struct ComputeSize
+ {
+ public readonly static ComputeSize VtgAsCompute = new ComputeSize(32, 32, 1);
+
+ public readonly int X;
+ public readonly int Y;
+ public readonly int Z;
+
+ public ComputeSize(int x, int y, int z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+ }
+}
diff --git a/src/Ryujinx.Graphics.GAL/Format.cs b/src/Ryujinx.Graphics.GAL/Format.cs
index 17c42d2d41..0eeae8e265 100644
--- a/src/Ryujinx.Graphics.GAL/Format.cs
+++ b/src/Ryujinx.Graphics.GAL/Format.cs
@@ -339,6 +339,84 @@ namespace Ryujinx.Graphics.GAL
return 1;
}
+ ///
+ /// Get bytes per element for this format.
+ ///
+ /// Texture format
+ /// Byte size for an element of this format (pixel, vertex attribute, etc)
+ public static int GetBytesPerElement(this Format format)
+ {
+ int scalarSize = format.GetScalarSize();
+
+ switch (format)
+ {
+ case Format.R8G8Unorm:
+ case Format.R8G8Snorm:
+ case Format.R8G8Uint:
+ case Format.R8G8Sint:
+ case Format.R8G8Uscaled:
+ case Format.R8G8Sscaled:
+ case Format.R16G16Float:
+ case Format.R16G16Unorm:
+ case Format.R16G16Snorm:
+ case Format.R16G16Uint:
+ case Format.R16G16Sint:
+ case Format.R16G16Uscaled:
+ case Format.R16G16Sscaled:
+ case Format.R32G32Float:
+ case Format.R32G32Uint:
+ case Format.R32G32Sint:
+ case Format.R32G32Uscaled:
+ case Format.R32G32Sscaled:
+ return 2 * scalarSize;
+
+ case Format.R8G8B8Unorm:
+ case Format.R8G8B8Snorm:
+ case Format.R8G8B8Uint:
+ case Format.R8G8B8Sint:
+ case Format.R8G8B8Uscaled:
+ case Format.R8G8B8Sscaled:
+ case Format.R16G16B16Float:
+ case Format.R16G16B16Unorm:
+ case Format.R16G16B16Snorm:
+ case Format.R16G16B16Uint:
+ case Format.R16G16B16Sint:
+ case Format.R16G16B16Uscaled:
+ case Format.R16G16B16Sscaled:
+ case Format.R32G32B32Float:
+ case Format.R32G32B32Uint:
+ case Format.R32G32B32Sint:
+ case Format.R32G32B32Uscaled:
+ case Format.R32G32B32Sscaled:
+ return 3 * scalarSize;
+
+ case Format.R8G8B8A8Unorm:
+ case Format.R8G8B8A8Snorm:
+ case Format.R8G8B8A8Uint:
+ case Format.R8G8B8A8Sint:
+ case Format.R8G8B8A8Srgb:
+ case Format.R8G8B8A8Uscaled:
+ case Format.R8G8B8A8Sscaled:
+ case Format.B8G8R8A8Unorm:
+ case Format.B8G8R8A8Srgb:
+ case Format.R16G16B16A16Float:
+ case Format.R16G16B16A16Unorm:
+ case Format.R16G16B16A16Snorm:
+ case Format.R16G16B16A16Uint:
+ case Format.R16G16B16A16Sint:
+ case Format.R16G16B16A16Uscaled:
+ case Format.R16G16B16A16Sscaled:
+ case Format.R32G32B32A32Float:
+ case Format.R32G32B32A32Uint:
+ case Format.R32G32B32A32Sint:
+ case Format.R32G32B32A32Uscaled:
+ case Format.R32G32B32A32Sscaled:
+ return 4 * scalarSize;
+ }
+
+ return scalarSize;
+ }
+
///
/// Checks if the texture format is a depth or depth-stencil format.
///
diff --git a/src/Ryujinx.Graphics.GAL/IPipeline.cs b/src/Ryujinx.Graphics.GAL/IPipeline.cs
index e3eff93b32..cbf1bc3a22 100644
--- a/src/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/src/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.GAL
void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size);
- void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ);
+ void DispatchCompute(int groupsX, int groupsY, int groupsZ);
void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance);
void DrawIndexed(
diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs
index 36e0d836ab..65028378f6 100644
--- a/src/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs
+++ b/src/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs
@@ -6,23 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
private int _groupsX;
private int _groupsY;
private int _groupsZ;
- private int _groupSizeX;
- private int _groupSizeY;
- private int _groupSizeZ;
- public void Set(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
+ public void Set(int groupsX, int groupsY, int groupsZ)
{
_groupsX = groupsX;
_groupsY = groupsY;
_groupsZ = groupsZ;
- _groupSizeX = groupSizeX;
- _groupSizeY = groupSizeY;
- _groupSizeZ = groupSizeZ;
}
public static void Run(ref DispatchComputeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
- renderer.Pipeline.DispatchCompute(command._groupsX, command._groupsY, command._groupsZ, command._groupSizeX, command._groupSizeY, command._groupSizeZ);
+ renderer.Pipeline.DispatchCompute(command._groupsX, command._groupsY, command._groupsZ);
}
}
}
diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
index 5098f9bfc2..edd79d8a07 100644
--- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
+++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
@@ -63,9 +63,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand();
}
- public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
+ public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{
- _renderer.New().Set(groupsX, groupsY, groupsZ, groupSizeX, groupSizeY, groupSizeZ);
+ _renderer.New().Set(groupsX, groupsY, groupsZ);
_renderer.QueueCommand();
}
diff --git a/src/Ryujinx.Graphics.GAL/ShaderInfo.cs b/src/Ryujinx.Graphics.GAL/ShaderInfo.cs
index 2fd3227dc1..c7965a03df 100644
--- a/src/Ryujinx.Graphics.GAL/ShaderInfo.cs
+++ b/src/Ryujinx.Graphics.GAL/ShaderInfo.cs
@@ -4,23 +4,22 @@ namespace Ryujinx.Graphics.GAL
{
public int FragmentOutputMap { get; }
public ResourceLayout ResourceLayout { get; }
+ public ComputeSize ComputeLocalSize { get; }
public ProgramPipelineState? State { get; }
public bool FromCache { get; set; }
- public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, ProgramPipelineState state, bool fromCache = false)
+ public ShaderInfo(
+ int fragmentOutputMap,
+ ResourceLayout resourceLayout,
+ ComputeSize computeLocalSize,
+ ProgramPipelineState? state,
+ bool fromCache = false)
{
FragmentOutputMap = fragmentOutputMap;
ResourceLayout = resourceLayout;
+ ComputeLocalSize = computeLocalSize;
State = state;
FromCache = fromCache;
}
-
- public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, bool fromCache = false)
- {
- FragmentOutputMap = fragmentOutputMap;
- ResourceLayout = resourceLayout;
- State = null;
- FromCache = fromCache;
- }
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
index 98c0ffa20d..cd81447240 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
@@ -200,7 +200,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
_channel.BufferManager.CommitComputeBindings();
- _context.Renderer.Pipeline.DispatchCompute(qmd.CtaRasterWidth, qmd.CtaRasterHeight, qmd.CtaRasterDepth, qmd.CtaThreadDimension0, qmd.CtaThreadDimension1, qmd.CtaThreadDimension2);
+ _context.Renderer.Pipeline.DispatchCompute(qmd.CtaRasterWidth, qmd.CtaRasterHeight, qmd.CtaRasterDepth);
_3dEngine.ForceShaderUpdate();
}
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs
index 6de50fb2e7..6dba27a7d7 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeContext.cs
@@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
1,
1,
1,
- 1,
+ format.GetBytesPerElement(),
format,
DepthStencilMode.Depth,
Target.TextureBuffer,
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
index 16ae83e6f7..73682866ba 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VtgAsComputeState.cs
@@ -211,10 +211,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
_context.Renderer.Pipeline.DispatchCompute(
BitUtils.DivRoundUp(_count, ComputeLocalSize),
BitUtils.DivRoundUp(_instanceCount, ComputeLocalSize),
- 1,
- ComputeLocalSize,
- ComputeLocalSize,
- ComputeLocalSize);
+ 1);
}
///
@@ -263,10 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
_context.Renderer.Pipeline.DispatchCompute(
BitUtils.DivRoundUp(primitivesCount, ComputeLocalSize),
BitUtils.DivRoundUp(_instanceCount, ComputeLocalSize),
- _geometryAsCompute.Info.ThreadsPerInputPrimitive,
- ComputeLocalSize,
- ComputeLocalSize,
- ComputeLocalSize);
+ _geometryAsCompute.Info.ThreadsPerInputPrimitive);
}
///
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index c4b5a13801..106cc26732 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
@@ -392,7 +392,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
context,
shaders,
specState.PipelineState,
- specState.TransformFeedbackDescriptors != null);
+ specState.TransformFeedbackDescriptors != null,
+ specState.ComputeState.GetLocalSize());
IProgram hostProgram;
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
index 20f96462ea..74922d1e3d 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
@@ -490,7 +490,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
- ShaderInfoBuilder shaderInfoBuilder = new(_context, compilation.SpecializationState.TransformFeedbackDescriptors != null);
+ ref GpuChannelComputeState computeState = ref compilation.SpecializationState.ComputeState;
+
+ ShaderInfoBuilder shaderInfoBuilder = new(
+ _context,
+ compilation.SpecializationState.TransformFeedbackDescriptors != null,
+ computeLocalSize: computeState.GetLocalSize());
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
{
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs
index d8cdbc3485..720f7e796f 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuChannelComputeState.cs
@@ -1,3 +1,5 @@
+using Ryujinx.Graphics.GAL;
+
namespace Ryujinx.Graphics.Gpu.Shader
{
///
@@ -61,5 +63,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
SharedMemorySize = sharedMemorySize;
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
}
+
+ ///
+ /// Gets the local group size of the shader in a GAL compatible struct.
+ ///
+ /// Local group size
+ public ComputeSize GetLocalSize()
+ {
+ return new ComputeSize(LocalSizeX, LocalSizeY, LocalSizeZ);
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index c67c6a2d68..64ea7c9795 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -224,7 +224,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
TranslatedShader translatedShader = TranslateShader(_dumper, channel, translatorContext, cachedGuestCode, asCompute: false);
ShaderSource[] shaderSourcesArray = new ShaderSource[] { CreateShaderSource(translatedShader.Program) };
- ShaderInfo info = ShaderInfoBuilder.BuildForCompute(_context, translatedShader.Program.Info);
+ ShaderInfo info = ShaderInfoBuilder.BuildForCompute(
+ _context,
+ translatedShader.Program.Info,
+ computeState.GetLocalSize());
IProgram hostProgram = _context.Renderer.CreateProgram(shaderSourcesArray, info);
cpShader = new CachedShaderProgram(hostProgram, specState, translatedShader.Shader);
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs
index 42b2cbb59b..6a46226772 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderInfoBuilder.cs
@@ -22,6 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
ResourceStages.Geometry;
private readonly GpuContext _context;
+ private readonly ComputeSize _computeLocalSize;
private int _fragmentOutputMap;
@@ -39,9 +40,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// GPU context that owns the shaders that will be added to the builder
/// Indicates if the graphics shader is used with transform feedback enabled
/// Indicates that the vertex shader will be emulated on a compute shader
- public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false)
+ /// Indicates the local thread size for a compute shader
+ public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false, ComputeSize computeLocalSize = default)
{
_context = context;
+ _computeLocalSize = computeLocalSize;
_fragmentOutputMap = -1;
@@ -353,14 +356,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
ResourceLayout resourceLayout = new(descriptors.AsReadOnly(), usages.AsReadOnly());
- if (pipeline.HasValue)
- {
- return new ShaderInfo(_fragmentOutputMap, resourceLayout, pipeline.Value, fromCache);
- }
- else
- {
- return new ShaderInfo(_fragmentOutputMap, resourceLayout, fromCache);
- }
+ return new ShaderInfo(_fragmentOutputMap, resourceLayout, _computeLocalSize, pipeline, fromCache);
}
///
@@ -370,14 +366,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Shaders from the disk cache
/// Optional pipeline for background compilation
/// Indicates if the graphics shader is used with transform feedback enabled
+ /// Compute local thread size
/// Shader information
public static ShaderInfo BuildForCache(
GpuContext context,
IEnumerable programs,
ProgramPipelineState? pipeline,
- bool tfEnabled)
+ bool tfEnabled,
+ ComputeSize computeLocalSize)
{
- ShaderInfoBuilder builder = new(context, tfEnabled);
+ ShaderInfoBuilder builder = new(context, tfEnabled, computeLocalSize: computeLocalSize);
foreach (CachedShaderStage program in programs)
{
@@ -395,11 +393,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
/// GPU context that owns the shader
/// Compute shader information
+ /// Compute local thread size
/// True if the compute shader comes from a disk cache, false otherwise
/// Shader information
- public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, bool fromCache = false)
+ public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, ComputeSize computeLocalSize, bool fromCache = false)
{
- ShaderInfoBuilder builder = new(context, tfEnabled: false, vertexAsCompute: false);
+ ShaderInfoBuilder builder = new(context, tfEnabled: false, vertexAsCompute: false, computeLocalSize: computeLocalSize);
builder.AddStageInfo(info);
@@ -416,7 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Shader information
public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, bool tfEnabled, bool fromCache = false)
{
- ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true);
+ ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true, computeLocalSize: ComputeSize.VtgAsCompute);
builder.AddStageInfo(info, vertexAsCompute: true);
diff --git a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
index 62c965697c..db0e8ffa7b 100644
--- a/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
+++ b/src/Ryujinx.Graphics.Metal/EncoderStateManager.cs
@@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.Metal
public readonly PrimitiveTopology Topology => _currentState.Topology;
public readonly Texture[] RenderTargets => _currentState.RenderTargets;
public readonly Texture DepthStencil => _currentState.DepthStencil;
+ public readonly ComputeSize ComputeLocalSize => _currentState.ComputeProgram.ComputeLocalSize;
// RGBA32F is the biggest format
private const int ZeroBufferSize = 4 * 4;
@@ -811,6 +812,7 @@ namespace Ryujinx.Graphics.Metal
Logger.Warning?.Print(LogClass.Gpu, $"Texture binding ({binding}) must be <= {Constants.MaxTexturesPerStage}");
return;
}
+
switch (stage)
{
case ShaderStage.Fragment:
@@ -852,10 +854,14 @@ namespace Ryujinx.Graphics.Metal
}
}
- public void UpdateTextureAndSampler(ShaderStage stage, ulong binding, TextureBase texture, MTLSamplerState sampler)
+ public void UpdateTextureAndSampler(ShaderStage stage, ulong binding, TextureBase texture, Sampler sampler)
{
UpdateTexture(stage, binding, texture);
- UpdateSampler(stage, binding, sampler);
+
+ if (sampler != null)
+ {
+ UpdateSampler(stage, binding, sampler.GetSampler());
+ }
}
private readonly void SetDepthStencilState(MTLRenderCommandEncoder renderCommandEncoder)
diff --git a/src/Ryujinx.Graphics.Metal/HelperShader.cs b/src/Ryujinx.Graphics.Metal/HelperShader.cs
index ec944b0f8c..5525186f63 100644
--- a/src/Ryujinx.Graphics.Metal/HelperShader.cs
+++ b/src/Ryujinx.Graphics.Metal/HelperShader.cs
@@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Metal
_programStrideChange = new Program(
[
new ShaderSource(strideChangeSource, ShaderStage.Compute, TargetLanguage.Msl)
- ], device);
+ ], device, new ComputeSize(64, 1, 1));
}
private static string ReadMsl(string fileName)
@@ -260,7 +260,7 @@ namespace Ryujinx.Graphics.Metal
_pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programStrideChange);
- _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1, 64, 1, 1);
+ _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
// Restore previous state
_pipeline.SwapState(null);
diff --git a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs
index c68da5a4ad..a0d6faced0 100644
--- a/src/Ryujinx.Graphics.Metal/MetalRenderer.cs
+++ b/src/Ryujinx.Graphics.Metal/MetalRenderer.cs
@@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.Metal
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{
- return new Program(shaders, _device);
+ return new Program(shaders, _device, info.ComputeLocalSize);
}
public ISampler CreateSampler(SamplerCreateInfo info)
@@ -104,7 +104,7 @@ namespace Ryujinx.Graphics.Metal
{
if (info.Target == Target.TextureBuffer)
{
- return new TextureBuffer(this, info);
+ return new TextureBuffer(_device, this, _pipeline, info);
}
return new Texture(_device, this, _pipeline, info);
diff --git a/src/Ryujinx.Graphics.Metal/Pipeline.cs b/src/Ryujinx.Graphics.Metal/Pipeline.cs
index 6363eb5d81..f410c789cf 100644
--- a/src/Ryujinx.Graphics.Metal/Pipeline.cs
+++ b/src/Ryujinx.Graphics.Metal/Pipeline.cs
@@ -347,13 +347,15 @@ namespace Ryujinx.Graphics.Metal
BufferHolder.Copy(this, Cbs, srcBuffer, dstBuffer, srcOffset, dstOffset, size);
}
- public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
+ public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{
var computeCommandEncoder = GetOrCreateComputeEncoder(true);
+ ComputeSize localSize = _encoderStateManager.ComputeLocalSize;
+
computeCommandEncoder.DispatchThreadgroups(
new MTLSize { width = (ulong)groupsX, height = (ulong)groupsY, depth = (ulong)groupsZ },
- new MTLSize { width = (ulong)groupSizeX, height = (ulong)groupSizeY, depth = (ulong)groupSizeZ });
+ new MTLSize { width = (ulong)localSize.X, height = (ulong)localSize.Y, depth = (ulong)localSize.Z });
}
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
@@ -658,12 +660,11 @@ namespace Ryujinx.Graphics.Metal
{
if (texture is TextureBase tex)
{
- if (sampler is Sampler samp)
+ if (sampler == null || sampler is Sampler)
{
- var mtlSampler = samp.GetSampler();
var index = (ulong)binding;
- _encoderStateManager.UpdateTextureAndSampler(stage, index, tex, mtlSampler);
+ _encoderStateManager.UpdateTextureAndSampler(stage, index, tex, (Sampler)sampler);
}
}
}
diff --git a/src/Ryujinx.Graphics.Metal/Program.cs b/src/Ryujinx.Graphics.Metal/Program.cs
index 40cb6df773..5635b711c4 100644
--- a/src/Ryujinx.Graphics.Metal/Program.cs
+++ b/src/Ryujinx.Graphics.Metal/Program.cs
@@ -15,13 +15,16 @@ namespace Ryujinx.Graphics.Metal
public MTLFunction VertexFunction;
public MTLFunction FragmentFunction;
public MTLFunction ComputeFunction;
+ public ComputeSize ComputeLocalSize { get; }
private HashTableSlim _graphicsPipelineCache;
private MTLComputePipelineState? _computePipelineCache;
private bool _firstBackgroundUse;
- public Program(ShaderSource[] shaders, MTLDevice device)
+ public Program(ShaderSource[] shaders, MTLDevice device, ComputeSize computeLocalSize = default)
{
+ ComputeLocalSize = computeLocalSize;
+
for (int index = 0; index < shaders.Length; index++)
{
ShaderSource shader = shaders[index];
diff --git a/src/Ryujinx.Graphics.Metal/State/PipelineState.cs b/src/Ryujinx.Graphics.Metal/State/PipelineState.cs
index c6e548c959..fa6d5410be 100644
--- a/src/Ryujinx.Graphics.Metal/State/PipelineState.cs
+++ b/src/Ryujinx.Graphics.Metal/State/PipelineState.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.GAL;
using SharpMetal.Foundation;
using SharpMetal.Metal;
using System;
@@ -249,6 +250,27 @@ namespace Ryujinx.Graphics.Metal
return pipelineState;
}
+ public static MTLComputePipelineDescriptor CreateComputeDescriptor(Program program)
+ {
+ ComputeSize localSize = program.ComputeLocalSize;
+
+ uint maxThreads = (uint)(localSize.X * localSize.Y * localSize.Z);
+
+ if (maxThreads == 0)
+ {
+ throw new InvalidOperationException($"Local thread size for compute cannot be 0 in any dimension.");
+ }
+
+ var descriptor = new MTLComputePipelineDescriptor
+ {
+ ComputeFunction = program.ComputeFunction,
+ MaxTotalThreadsPerThreadgroup = maxThreads,
+ ThreadGroupSizeIsMultipleOfThreadExecutionWidth = true,
+ };
+
+ return descriptor;
+ }
+
public static MTLComputePipelineState CreateComputePipeline(MTLDevice device, Program program)
{
if (program.TryGetComputePipeline(out var pipelineState))
@@ -256,8 +278,10 @@ namespace Ryujinx.Graphics.Metal
return pipelineState;
}
+ using MTLComputePipelineDescriptor descriptor = CreateComputeDescriptor(program);
+
var error = new NSError(IntPtr.Zero);
- pipelineState = device.NewComputePipelineState(program.ComputeFunction, ref error);
+ pipelineState = device.NewComputePipelineState(descriptor, MTLPipelineOption.None, 0, ref error);
if (error != IntPtr.Zero)
{
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create Compute Pipeline State: {StringHelper.String(error.LocalizedDescription)}");
diff --git a/src/Ryujinx.Graphics.Metal/Texture.cs b/src/Ryujinx.Graphics.Metal/Texture.cs
index 668ddd8bee..fdff81f0d0 100644
--- a/src/Ryujinx.Graphics.Metal/Texture.cs
+++ b/src/Ryujinx.Graphics.Metal/Texture.cs
@@ -37,7 +37,9 @@ namespace Ryujinx.Graphics.Metal
descriptor.Swizzle = GetSwizzle(info, descriptor.PixelFormat);
_mtlTexture = _device.NewTexture(descriptor);
+
MtlFormat = pixelFormat;
+ descriptor.Dispose();
}
public Texture(MTLDevice device, MetalRenderer renderer, Pipeline pipeline, TextureCreateInfo info, MTLTexture sourceTexture, int firstLayer, int firstLevel) : base(device, renderer, pipeline, info)
diff --git a/src/Ryujinx.Graphics.Metal/TextureBase.cs b/src/Ryujinx.Graphics.Metal/TextureBase.cs
index 96daf8d3bd..fcd07a66ae 100644
--- a/src/Ryujinx.Graphics.Metal/TextureBase.cs
+++ b/src/Ryujinx.Graphics.Metal/TextureBase.cs
@@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Metal
return _mtlTexture;
}
- public void Release()
+ public virtual void Release()
{
Dispose();
}
diff --git a/src/Ryujinx.Graphics.Metal/TextureBuffer.cs b/src/Ryujinx.Graphics.Metal/TextureBuffer.cs
index 3db1e7c4a8..033e12105b 100644
--- a/src/Ryujinx.Graphics.Metal/TextureBuffer.cs
+++ b/src/Ryujinx.Graphics.Metal/TextureBuffer.cs
@@ -7,27 +7,54 @@ using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
- class TextureBuffer : ITexture
+ class TextureBuffer : TextureBase, ITexture
{
- private readonly MetalRenderer _renderer;
-
+ private MTLTextureDescriptor _descriptor;
private BufferHandle _bufferHandle;
private int _offset;
private int _size;
private int _bufferCount;
- public int Width { get; }
- public int Height { get; }
-
- public MTLPixelFormat MtlFormat { get; }
-
- public TextureBuffer(MetalRenderer renderer, TextureCreateInfo info)
+ public TextureBuffer(MTLDevice device, MetalRenderer renderer, Pipeline pipeline, TextureCreateInfo info) : base(device, renderer, pipeline, info)
{
- _renderer = renderer;
- Width = info.Width;
- Height = info.Height;
- MtlFormat = FormatTable.GetFormat(info.Format);
+ MTLPixelFormat pixelFormat = FormatTable.GetFormat(Info.Format);
+
+ _descriptor = new MTLTextureDescriptor
+ {
+ PixelFormat = pixelFormat,
+ Usage = MTLTextureUsage.Unknown,
+ TextureType = MTLTextureType.TextureBuffer,
+ Width = (ulong)Info.Width,
+ Height = (ulong)Info.Height,
+ };
+
+ MtlFormat = pixelFormat;
+ }
+
+ private void RebuildStorage()
+ {
+ // Find the parent buffer, and try to build a texture from it.
+
+ // TODO: texture uses should register read/write usage on the assigned buffer.
+ Auto bufferAuto = _renderer.BufferManager.GetBuffer(_bufferHandle, false);
+
+ if (_mtlTexture.NativePtr != 0)
+ {
+ _mtlTexture.Dispose();
+ }
+
+ if (bufferAuto == null)
+ {
+ _mtlTexture = default;
+ }
+ else
+ {
+ DisposableBuffer buffer = bufferAuto.Get(_pipeline.Cbs, _offset, _size);
+
+ _descriptor.Width = (uint)(_size / Info.BytesPerPixel);
+ _mtlTexture = buffer.Value.NewTexture(_descriptor, (ulong)_offset, (ulong)_size);
+ }
}
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
@@ -65,11 +92,6 @@ namespace Ryujinx.Graphics.Metal
throw new NotImplementedException();
}
- public void Release()
- {
-
- }
-
public void SetData(IMemoryOwner data)
{
_renderer.SetBufferData(_bufferHandle, _offset, data.Memory.Span);
@@ -101,7 +123,14 @@ namespace Ryujinx.Graphics.Metal
_size = buffer.Size;
_bufferCount = _renderer.BufferManager.BufferCount;
- Release();
+ RebuildStorage();
+ }
+
+ public override void Release()
+ {
+ _descriptor.Dispose();
+
+ base.Release();
}
}
}
diff --git a/src/Ryujinx.Graphics.Metal/Window.cs b/src/Ryujinx.Graphics.Metal/Window.cs
index 38ee6459ba..6489b591d9 100644
--- a/src/Ryujinx.Graphics.Metal/Window.cs
+++ b/src/Ryujinx.Graphics.Metal/Window.cs
@@ -18,6 +18,10 @@ namespace Ryujinx.Graphics.Metal
private int _width;
private int _height;
+
+ private int _requestedWidth;
+ private int _requestedHeight;
+
// private bool _vsyncEnabled;
private AntiAliasing _currentAntiAliasing;
private bool _updateEffect;
@@ -35,10 +39,26 @@ namespace Ryujinx.Graphics.Metal
_metalLayer = metalLayer;
}
- public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
+ private unsafe void ResizeIfNeeded()
+ {
+ if (_requestedWidth != 0 && _requestedHeight != 0)
+ {
+ // TODO: This is actually a CGSize, but there is no overload for that, so fill the first two fields of rect with the size.
+ var rect = new NSRect(_requestedWidth, _requestedHeight, 0, 0);
+
+ ObjectiveC.objc_msgSend(_metalLayer, "setDrawableSize:", rect);
+
+ _requestedWidth = 0;
+ _requestedHeight = 0;
+ }
+ }
+
+ public unsafe void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
{
if (_renderer.Pipeline is Pipeline pipeline && texture is Texture tex)
{
+ ResizeIfNeeded();
+
var drawable = new CAMetalDrawable(ObjectiveC.IntPtr_objc_msgSend(_metalLayer, "nextDrawable"));
_width = (int)drawable.Texture.Width;
@@ -114,7 +134,8 @@ namespace Ryujinx.Graphics.Metal
public void SetSize(int width, int height)
{
- // Ignore
+ _requestedWidth = width;
+ _requestedHeight = height;
}
public void ChangeVSyncMode(bool vsyncEnabled)
diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs
index acfab5ff71..54f6b3f7b2 100644
--- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -205,7 +205,7 @@ namespace Ryujinx.Graphics.OpenGL
Buffer.Copy(source, destination, srcOffset, dstOffset, size);
}
- public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
+ public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{
if (!_program.IsLinked)
{
diff --git a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs
index 3179c80a25..5fac994b35 100644
--- a/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs
+++ b/src/Ryujinx.Graphics.Shader/CodeGen/Msl/Declarations.cs
@@ -241,7 +241,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Msl
var textureTypeName = texture.Type.ToMslTextureType();
argBufferPointers[texture.Binding] = $"{textureTypeName} tex_{texture.Name};";
- if (!texture.Separate)
+ if (!texture.Separate && texture.Type != SamplerType.TextureBuffer)
{
argBufferPointers[Defaults.MaxTexturesPerStage + texture.Binding] = $"sampler samp_{texture.Name};";
}
diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs
index 9dbe28ecc4..5a5ddf8c8d 100644
--- a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs
@@ -155,7 +155,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
// Sharpening pass
@@ -163,7 +163,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) });
_pipeline.SetImage(0, destinationTexture);
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
_pipeline.Finish();
diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
index 9203171de9..c129333354 100644
--- a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
@@ -76,7 +76,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
_pipeline.SetImage(ShaderStage.Compute, 0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs
index 6b76548cdc..08e07f256b 100644
--- a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs
+++ b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs
@@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
// Blend pass
@@ -230,7 +230,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
// Neighbour pass
@@ -239,7 +239,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier();
_pipeline.Finish();
diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
index da0357c4fa..cb1cfa3294 100644
--- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
+++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Common;
+using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
@@ -861,7 +861,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programStrideChange);
- _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
_pipeline.Finish(gd, cbs);
}
@@ -1044,7 +1044,7 @@ namespace Ryujinx.Graphics.Vulkan
int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
if (srcView != src)
{
@@ -1170,7 +1170,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, format);
- _pipeline.DispatchCompute(dispatchX, dispatchY, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
if (srcView != src)
{
@@ -1582,7 +1582,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(3, patternScoped.Range) });
_pipeline.SetProgram(_programConvertIndirectData);
- _pipeline.DispatchCompute(1, 1, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(1, 1, 1);
BufferHolder.InsertBufferBarrier(
gd,
@@ -1684,7 +1684,7 @@ namespace Ryujinx.Graphics.Vulkan
_pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
- _pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1, 0, 0, 0);
+ _pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
_pipeline.Finish(gd, cbs);
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
index 2d9d54f8a8..3cded74159 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using Silk.NET.Vulkan;
using System;
@@ -348,7 +348,7 @@ namespace Ryujinx.Graphics.Vulkan
}
}
- public void DispatchCompute(int groupsX, int groupsY, int groupsZ, int groupSizeX, int groupSizeY, int groupSizeZ)
+ public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{
if (!_program.IsLinked)
{