Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7e9011673b | ||
|
741db8e43d | ||
|
3bd357045f | ||
|
ab5d77c0c4 | ||
|
7bfb5f79b8 | ||
|
8cc2479825 | ||
|
8f35345729 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -74,6 +74,9 @@ _TeamCity*
|
|||||||
# DotCover is a Code Coverage Tool
|
# DotCover is a Code Coverage Tool
|
||||||
*.dotCover
|
*.dotCover
|
||||||
|
|
||||||
|
# Rider is a Visual Studio alternative
|
||||||
|
.idea/*
|
||||||
|
|
||||||
# NCrunch
|
# NCrunch
|
||||||
*.ncrunch*
|
*.ncrunch*
|
||||||
.*crunch*.local.xml
|
.*crunch*.local.xml
|
||||||
|
@@ -100,9 +100,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
{
|
{
|
||||||
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
||||||
{
|
{
|
||||||
float inputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||||
|
|
||||||
float sampleInputMax = Math.Abs(inputSample * Parameter.InputGain);
|
float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
|
||||||
|
|
||||||
|
float sampleInputMax = Math.Abs(inputSample);
|
||||||
|
|
||||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
@@ -131,7 +133,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||||
|
|
||||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||||
|
|
||||||
|
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||||
|
|
||||||
delayedSample = inputSample;
|
delayedSample = inputSample;
|
||||||
|
|
||||||
|
@@ -111,9 +111,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
{
|
{
|
||||||
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
||||||
{
|
{
|
||||||
float inputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||||
|
|
||||||
float sampleInputMax = Math.Abs(inputSample * Parameter.InputGain);
|
float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
|
||||||
|
|
||||||
|
float sampleInputMax = Math.Abs(inputSample);
|
||||||
|
|
||||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||||
|
|
||||||
@@ -142,7 +144,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||||
|
|
||||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||||
|
|
||||||
|
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||||
|
|
||||||
delayedSample = inputSample;
|
delayedSample = inputSample;
|
||||||
|
|
||||||
|
@@ -76,7 +76,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation
|
DataSourceHelper.WaveBufferInformation info = new DataSourceHelper.WaveBufferInformation
|
||||||
{
|
{
|
||||||
SourceSampleRate = SampleRate,
|
SourceSampleRate = SampleRate,
|
||||||
SampleFormat = SampleFormat.PcmInt16,
|
SampleFormat = SampleFormat.PcmFloat,
|
||||||
Pitch = Pitch,
|
Pitch = Pitch,
|
||||||
DecodingBehaviour = DecodingBehaviour,
|
DecodingBehaviour = DecodingBehaviour,
|
||||||
ExtraParameter = 0,
|
ExtraParameter = 0,
|
||||||
|
@@ -600,19 +600,42 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
|
public static void ResampleForUpsampler(Span<float> outputBuffer, ReadOnlySpan<float> inputBuffer, float ratio, ref float fraction, int sampleCount)
|
||||||
{
|
{
|
||||||
// TODO: use a bandwidth filter to have better resampling.
|
// Currently a simple cubic interpolation, assuming duplicated values at edges.
|
||||||
|
// TODO: Discover and use algorithm that the switch uses.
|
||||||
|
|
||||||
int inputBufferIndex = 0;
|
int inputBufferIndex = 0;
|
||||||
|
int maxIndex = inputBuffer.Length - 1;
|
||||||
|
int cubicEnd = inputBuffer.Length - 3;
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
float outputData = inputBuffer[inputBufferIndex];
|
float s0, s1, s2, s3;
|
||||||
|
|
||||||
if (fraction > 1.0f)
|
s1 = inputBuffer[inputBufferIndex];
|
||||||
|
|
||||||
|
if (inputBufferIndex == 0 || inputBufferIndex > cubicEnd)
|
||||||
{
|
{
|
||||||
outputData = inputBuffer[inputBufferIndex + 1];
|
// Clamp interplation values at the ends of the input buffer.
|
||||||
|
s0 = inputBuffer[Math.Max(0, inputBufferIndex - 1)];
|
||||||
|
s2 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 1)];
|
||||||
|
s3 = inputBuffer[Math.Min(maxIndex, inputBufferIndex + 2)];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s0 = inputBuffer[inputBufferIndex - 1];
|
||||||
|
s2 = inputBuffer[inputBufferIndex + 1];
|
||||||
|
s3 = inputBuffer[inputBufferIndex + 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
outputBuffer[i] = outputData;
|
float a = s3 - s2 - s0 + s1;
|
||||||
|
float b = s0 - s1 - a;
|
||||||
|
float c = s2 - s0;
|
||||||
|
float d = s1;
|
||||||
|
|
||||||
|
float f2 = fraction * fraction;
|
||||||
|
float f3 = f2 * fraction;
|
||||||
|
|
||||||
|
outputBuffer[i] = a * f3 + b * f2 + c * fraction + d;
|
||||||
|
|
||||||
fraction += ratio;
|
fraction += ratio;
|
||||||
inputBufferIndex += (int)MathF.Truncate(fraction);
|
inputBufferIndex += (int)MathF.Truncate(fraction);
|
||||||
|
@@ -37,6 +37,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
|||||||
DectectorAverage.AsSpan().Fill(0.0f);
|
DectectorAverage.AsSpan().Fill(0.0f);
|
||||||
CompressionGain.AsSpan().Fill(1.0f);
|
CompressionGain.AsSpan().Fill(1.0f);
|
||||||
DelayedSampleBufferPosition.AsSpan().Fill(0);
|
DelayedSampleBufferPosition.AsSpan().Fill(0);
|
||||||
|
DelayedSampleBuffer.AsSpan().Fill(0.0f);
|
||||||
|
|
||||||
UpdateParameter(ref parameter);
|
UpdateParameter(ref parameter);
|
||||||
}
|
}
|
||||||
|
@@ -558,7 +558,16 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
|
if (_rendererContext.BehaviourContext.IsEffectInfoVersion2Supported())
|
||||||
{
|
{
|
||||||
Memory<EffectResultState> dspResultState = _effectContext.GetDspStateMemory(effectId);
|
Memory<EffectResultState> dspResultState;
|
||||||
|
|
||||||
|
if (effect.Parameter.StatisticsEnabled)
|
||||||
|
{
|
||||||
|
dspResultState = _effectContext.GetDspStateMemory(effectId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dspResultState = Memory<EffectResultState>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
_commandBuffer.GenerateLimiterEffectVersion2(bufferOffset, effect.Parameter, effect.State, dspResultState, effect.IsEnabled, workBuffer, nodeId);
|
_commandBuffer.GenerateLimiterEffectVersion2(bufferOffset, effect.Parameter, effect.State, dspResultState, effect.IsEnabled, workBuffer, nodeId);
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common
|
|
||||||
{
|
|
||||||
public static class EnumExtensions
|
|
||||||
{
|
|
||||||
public static T[] GetValues<T>()
|
|
||||||
{
|
|
||||||
return (T[])Enum.GetValues(typeof(T));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -94,7 +94,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
|
|
||||||
static Logger()
|
static Logger()
|
||||||
{
|
{
|
||||||
m_EnabledClasses = new bool[Enum.GetNames(typeof(LogClass)).Length];
|
m_EnabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
||||||
|
|
||||||
for (int index = 0; index < m_EnabledClasses.Length; index++)
|
for (int index = 0; index < m_EnabledClasses.Length; index++)
|
||||||
{
|
{
|
||||||
|
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
|
|
||||||
BufferHandle CreateBuffer(int size);
|
BufferHandle CreateBuffer(int size);
|
||||||
|
|
||||||
IProgram CreateProgram(IShader[] shaders);
|
IProgram CreateProgram(IShader[] shaders, ShaderInfo info);
|
||||||
|
|
||||||
ISampler CreateSampler(SamplerCreateInfo info);
|
ISampler CreateSampler(SamplerCreateInfo info);
|
||||||
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
ITexture CreateTexture(TextureCreateInfo info, float scale);
|
||||||
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
|
|
||||||
Capabilities GetCapabilities();
|
Capabilities GetCapabilities();
|
||||||
|
|
||||||
IProgram LoadProgramBinary(byte[] programBinary);
|
IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
|
||||||
|
|
||||||
void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);
|
void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);
|
||||||
|
|
||||||
|
@@ -5,17 +5,21 @@
|
|||||||
public ThreadedProgram Threaded { get; set; }
|
public ThreadedProgram Threaded { get; set; }
|
||||||
|
|
||||||
private byte[] _data;
|
private byte[] _data;
|
||||||
|
private bool _hasFragmentShader;
|
||||||
|
private ShaderInfo _info;
|
||||||
|
|
||||||
public BinaryProgramRequest(ThreadedProgram program, byte[] data)
|
public BinaryProgramRequest(ThreadedProgram program, byte[] data, bool hasFragmentShader, ShaderInfo info)
|
||||||
{
|
{
|
||||||
Threaded = program;
|
Threaded = program;
|
||||||
|
|
||||||
_data = data;
|
_data = data;
|
||||||
|
_hasFragmentShader = hasFragmentShader;
|
||||||
|
_info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram Create(IRenderer renderer)
|
public IProgram Create(IRenderer renderer)
|
||||||
{
|
{
|
||||||
return renderer.LoadProgramBinary(_data);
|
return renderer.LoadProgramBinary(_data, _hasFragmentShader, _info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,12 +7,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
|
|||||||
public ThreadedProgram Threaded { get; set; }
|
public ThreadedProgram Threaded { get; set; }
|
||||||
|
|
||||||
private IShader[] _shaders;
|
private IShader[] _shaders;
|
||||||
|
private ShaderInfo _info;
|
||||||
|
|
||||||
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders)
|
public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, ShaderInfo info)
|
||||||
{
|
{
|
||||||
Threaded = program;
|
Threaded = program;
|
||||||
|
|
||||||
_shaders = shaders;
|
_shaders = shaders;
|
||||||
|
_info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram Create(IRenderer renderer)
|
public IProgram Create(IRenderer renderer)
|
||||||
@@ -24,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
|
|||||||
return threaded?.Base;
|
return threaded?.Base;
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
return renderer.CreateProgram(shaders);
|
return renderer.CreateProgram(shaders, _info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram CreateProgram(IShader[] shaders)
|
public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
|
||||||
{
|
{
|
||||||
var program = new ThreadedProgram(this);
|
var program = new ThreadedProgram(this);
|
||||||
SourceProgramRequest request = new SourceProgramRequest(program, shaders);
|
SourceProgramRequest request = new SourceProgramRequest(program, shaders, info);
|
||||||
Programs.Add(request);
|
Programs.Add(request);
|
||||||
|
|
||||||
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
||||||
@@ -355,11 +355,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_baseRenderer.Initialize(logLevel);
|
_baseRenderer.Initialize(logLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram LoadProgramBinary(byte[] programBinary)
|
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
|
||||||
{
|
{
|
||||||
var program = new ThreadedProgram(this);
|
var program = new ThreadedProgram(this);
|
||||||
|
|
||||||
BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary);
|
BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary, hasFragmentShader, info);
|
||||||
Programs.Add(request);
|
Programs.Add(request);
|
||||||
|
|
||||||
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
|
||||||
|
12
Ryujinx.Graphics.GAL/ShaderInfo.cs
Normal file
12
Ryujinx.Graphics.GAL/ShaderInfo.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Ryujinx.Graphics.GAL
|
||||||
|
{
|
||||||
|
public struct ShaderInfo
|
||||||
|
{
|
||||||
|
public int FragmentOutputMap { get; }
|
||||||
|
|
||||||
|
public ShaderInfo(int fragmentOutputMap)
|
||||||
|
{
|
||||||
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -85,9 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
}
|
}
|
||||||
|
|
||||||
int alignWidth = Constants.StrideAlignment / bpp;
|
int alignWidth = Constants.StrideAlignment / bpp;
|
||||||
return tex.RegionX == 0 &&
|
return stride / bpp == BitUtils.AlignUp(xCount, alignWidth);
|
||||||
tex.RegionY == 0 &&
|
|
||||||
stride / bpp == BitUtils.AlignUp(xCount, alignWidth);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -161,6 +159,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
|
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
|
||||||
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
|
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
|
||||||
|
|
||||||
|
int srcRegionX = 0, srcRegionY = 0, dstRegionX = 0, dstRegionY = 0;
|
||||||
|
|
||||||
|
if (!srcLinear)
|
||||||
|
{
|
||||||
|
srcRegionX = src.RegionX;
|
||||||
|
srcRegionY = src.RegionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dstLinear)
|
||||||
|
{
|
||||||
|
dstRegionX = dst.RegionX;
|
||||||
|
dstRegionY = dst.RegionY;
|
||||||
|
}
|
||||||
|
|
||||||
int srcStride = (int)_state.State.PitchIn;
|
int srcStride = (int)_state.State.PitchIn;
|
||||||
int dstStride = (int)_state.State.PitchOut;
|
int dstStride = (int)_state.State.PitchOut;
|
||||||
|
|
||||||
@@ -182,8 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
dst.MemoryLayout.UnpackGobBlocksInZ(),
|
dst.MemoryLayout.UnpackGobBlocksInZ(),
|
||||||
dstBpp);
|
dstBpp);
|
||||||
|
|
||||||
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(src.RegionX, src.RegionY, xCount, yCount);
|
(int srcBaseOffset, int srcSize) = srcCalculator.GetRectangleRange(srcRegionX, srcRegionY, xCount, yCount);
|
||||||
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dst.RegionX, dst.RegionY, xCount, yCount);
|
(int dstBaseOffset, int dstSize) = dstCalculator.GetRectangleRange(dstRegionX, dstRegionY, xCount, yCount);
|
||||||
|
|
||||||
if (srcLinear && srcStride < 0)
|
if (srcLinear && srcStride < 0)
|
||||||
{
|
{
|
||||||
@@ -272,13 +284,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||||||
|
|
||||||
for (int y = 0; y < yCount; y++)
|
for (int y = 0; y < yCount; y++)
|
||||||
{
|
{
|
||||||
srcCalculator.SetY(src.RegionY + y);
|
srcCalculator.SetY(srcRegionY + y);
|
||||||
dstCalculator.SetY(dst.RegionY + y);
|
dstCalculator.SetY(dstRegionY + y);
|
||||||
|
|
||||||
for (int x = 0; x < xCount; x++)
|
for (int x = 0; x < xCount; x++)
|
||||||
{
|
{
|
||||||
int srcOffset = srcCalculator.GetOffset(src.RegionX + x);
|
int srcOffset = srcCalculator.GetOffset(srcRegionX + x);
|
||||||
int dstOffset = dstCalculator.GetOffset(dst.RegionX + x);
|
int dstOffset = dstCalculator.GetOffset(dstRegionX + x);
|
||||||
|
|
||||||
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
*(T*)(dstBase + dstOffset) = *(T*)(srcBase + srcOffset);
|
||||||
}
|
}
|
||||||
|
@@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
_ilGen.Emit(OpCodes.Ret);
|
_ilGen.Emit(OpCodes.Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (MacroExecute)_meth.CreateDelegate(typeof(MacroExecute));
|
return _meth.CreateDelegate<MacroExecute>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -77,7 +77,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||||||
programInfo.Images.Count,
|
programInfo.Images.Count,
|
||||||
programInfo.UsesInstanceId,
|
programInfo.UsesInstanceId,
|
||||||
programInfo.UsesRtLayer,
|
programInfo.UsesRtLayer,
|
||||||
programInfo.ClipDistancesWritten);
|
programInfo.ClipDistancesWritten,
|
||||||
|
programInfo.FragmentOutputMap);
|
||||||
CBuffers = programInfo.CBuffers.ToArray();
|
CBuffers = programInfo.CBuffers.ToArray();
|
||||||
SBuffers = programInfo.SBuffers.ToArray();
|
SBuffers = programInfo.SBuffers.ToArray();
|
||||||
Textures = programInfo.Textures.ToArray();
|
Textures = programInfo.Textures.ToArray();
|
||||||
@@ -97,7 +98,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||||||
Images,
|
Images,
|
||||||
Header.UseFlags.HasFlag(UseFlags.InstanceId),
|
Header.UseFlags.HasFlag(UseFlags.InstanceId),
|
||||||
Header.UseFlags.HasFlag(UseFlags.RtLayer),
|
Header.UseFlags.HasFlag(UseFlags.RtLayer),
|
||||||
Header.ClipDistancesWritten);
|
Header.ClipDistancesWritten,
|
||||||
|
Header.FragmentOutputMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Host shader entry header used for binding information.
|
/// Host shader entry header used for binding information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x14)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)]
|
||||||
struct HostShaderCacheEntryHeader
|
struct HostShaderCacheEntryHeader
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -70,6 +70,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public byte Reserved;
|
public byte Reserved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mask of components written by the fragment shader stage.
|
||||||
|
/// </summary>
|
||||||
|
public int FragmentOutputMap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new host shader cache entry header.
|
/// Create a new host shader cache entry header.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -78,6 +83,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||||||
/// <param name="texturesCount">Count of texture descriptors</param>
|
/// <param name="texturesCount">Count of texture descriptors</param>
|
||||||
/// <param name="imagesCount">Count of image descriptors</param>
|
/// <param name="imagesCount">Count of image descriptors</param>
|
||||||
/// <param name="usesInstanceId">Set to true if the shader uses instance id</param>
|
/// <param name="usesInstanceId">Set to true if the shader uses instance id</param>
|
||||||
|
/// <param name="clipDistancesWritten">Mask of clip distances that are written to on the shader</param>
|
||||||
|
/// <param name="fragmentOutputMap">Mask of components written by the fragment shader stage</param>
|
||||||
public HostShaderCacheEntryHeader(
|
public HostShaderCacheEntryHeader(
|
||||||
int cBuffersCount,
|
int cBuffersCount,
|
||||||
int sBuffersCount,
|
int sBuffersCount,
|
||||||
@@ -85,13 +92,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
|
|||||||
int imagesCount,
|
int imagesCount,
|
||||||
bool usesInstanceId,
|
bool usesInstanceId,
|
||||||
bool usesRtLayer,
|
bool usesRtLayer,
|
||||||
byte clipDistancesWritten) : this()
|
byte clipDistancesWritten,
|
||||||
|
int fragmentOutputMap) : this()
|
||||||
{
|
{
|
||||||
CBuffersCount = cBuffersCount;
|
CBuffersCount = cBuffersCount;
|
||||||
SBuffersCount = sBuffersCount;
|
SBuffersCount = sBuffersCount;
|
||||||
TexturesCount = texturesCount;
|
TexturesCount = texturesCount;
|
||||||
ImagesCount = imagesCount;
|
ImagesCount = imagesCount;
|
||||||
ClipDistancesWritten = clipDistancesWritten;
|
ClipDistancesWritten = clipDistancesWritten;
|
||||||
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
InUse = true;
|
InUse = true;
|
||||||
|
|
||||||
UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None;
|
UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None;
|
||||||
|
@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the codegen (to be changed when codegen or guest format change).
|
/// Version of the codegen (to be changed when codegen or guest format change).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const ulong ShaderCodeGenVersion = 3106;
|
private const ulong ShaderCodeGenVersion = 3063;
|
||||||
|
|
||||||
// Progress reporting helpers
|
// Progress reporting helpers
|
||||||
private volatile int _shaderCount;
|
private volatile int _shaderCount;
|
||||||
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
|
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
|
||||||
hostProgramBinary = hostProgramBinarySpan.ToArray();
|
hostProgramBinary = hostProgramBinarySpan.ToArray();
|
||||||
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
|
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, false, new ShaderInfo(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
|
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
|
||||||
@@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
// Compile shader and create program as the shader program binary got invalidated.
|
// Compile shader and create program as the shader program binary got invalidated.
|
||||||
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
|
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
|
||||||
hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
|
hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
|
||||||
|
|
||||||
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
||||||
{
|
{
|
||||||
@@ -303,7 +303,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
|
hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
|
||||||
hostProgramBinary = hostProgramBinarySpan.ToArray();
|
hostProgramBinary = hostProgramBinarySpan.ToArray();
|
||||||
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
|
|
||||||
|
bool hasFragmentShader = false;
|
||||||
|
int fragmentOutputMap = -1;
|
||||||
|
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||||
|
|
||||||
|
if (hostShaderEntries[fragmentIndex] != null && hostShaderEntries[fragmentIndex].Header.InUse)
|
||||||
|
{
|
||||||
|
hasFragmentShader = true;
|
||||||
|
fragmentOutputMap = hostShaderEntries[fragmentIndex].Header.FragmentOutputMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, hasFragmentShader, new ShaderInfo(fragmentOutputMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
|
ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
|
||||||
@@ -426,7 +437,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
hostShaders.Add(hostShader);
|
hostShaders.Add(hostShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
|
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||||
|
int fragmentOutputMap = -1;
|
||||||
|
|
||||||
|
if (shaders[fragmentIndex] != null)
|
||||||
|
{
|
||||||
|
fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
|
||||||
|
|
||||||
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
|
||||||
{
|
{
|
||||||
@@ -617,7 +636,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
|
shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
|
||||||
|
|
||||||
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
|
IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
|
||||||
|
|
||||||
cpShader = new ShaderBundle(hostProgram, shader);
|
cpShader = new ShaderBundle(hostProgram, shader);
|
||||||
|
|
||||||
@@ -755,7 +774,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
hostShaders.Add(hostShader);
|
hostShaders.Add(hostShader);
|
||||||
}
|
}
|
||||||
|
|
||||||
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
|
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||||
|
int fragmentOutputMap = -1;
|
||||||
|
|
||||||
|
if (shaders[fragmentIndex] != null)
|
||||||
|
{
|
||||||
|
fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
|
||||||
|
|
||||||
gpShaders = new ShaderBundle(hostProgram, shaders);
|
gpShaders = new ShaderBundle(hostProgram, shaders);
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
|
|
||||||
static FormatTable()
|
static FormatTable()
|
||||||
{
|
{
|
||||||
int tableSize = Enum.GetNames(typeof(Format)).Length;
|
int tableSize = Enum.GetNames<Format>().Length;
|
||||||
|
|
||||||
Table = new FormatInfo[tableSize];
|
Table = new FormatInfo[tableSize];
|
||||||
TableImage = new SizedInternalFormat[tableSize];
|
TableImage = new SizedInternalFormat[tableSize];
|
||||||
|
@@ -53,7 +53,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
private ClipOrigin _clipOrigin;
|
private ClipOrigin _clipOrigin;
|
||||||
private ClipDepthMode _clipDepthMode;
|
private ClipDepthMode _clipDepthMode;
|
||||||
|
|
||||||
private readonly uint[] _componentMasks;
|
private uint _fragmentOutputMap;
|
||||||
|
private uint _componentMasks;
|
||||||
|
private uint _currentComponentMasks;
|
||||||
|
|
||||||
private uint _scissorEnables;
|
private uint _scissorEnables;
|
||||||
|
|
||||||
@@ -73,12 +75,8 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_clipOrigin = ClipOrigin.LowerLeft;
|
_clipOrigin = ClipOrigin.LowerLeft;
|
||||||
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
|
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
|
||||||
|
|
||||||
_componentMasks = new uint[Constants.MaxRenderTargets];
|
_fragmentOutputMap = uint.MaxValue;
|
||||||
|
_componentMasks = uint.MaxValue;
|
||||||
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
|
||||||
{
|
|
||||||
_componentMasks[index] = 0xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
|
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
|
||||||
new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
|
new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
|
||||||
@@ -1001,18 +999,30 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
|
|
||||||
public void SetProgram(IProgram program)
|
public void SetProgram(IProgram program)
|
||||||
{
|
{
|
||||||
_program = (Program)program;
|
Program prg = (Program)program;
|
||||||
|
|
||||||
if (_tfEnabled)
|
if (_tfEnabled)
|
||||||
{
|
{
|
||||||
GL.EndTransformFeedback();
|
GL.EndTransformFeedback();
|
||||||
_program.Bind();
|
prg.Bind();
|
||||||
GL.BeginTransformFeedback(_tfTopology);
|
GL.BeginTransformFeedback(_tfTopology);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_program.Bind();
|
prg.Bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap)
|
||||||
|
{
|
||||||
|
_fragmentOutputMap = (uint)prg.FragmentOutputMap;
|
||||||
|
|
||||||
|
for (int index = 0; index < Constants.MaxRenderTargets; index++)
|
||||||
|
{
|
||||||
|
RestoreComponentMask(index, force: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_program = prg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRasterizerDiscard(bool discard)
|
public void SetRasterizerDiscard(bool discard)
|
||||||
@@ -1037,11 +1047,13 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
|
|
||||||
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
|
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
|
||||||
{
|
{
|
||||||
|
_componentMasks = 0;
|
||||||
|
|
||||||
for (int index = 0; index < componentMasks.Length; index++)
|
for (int index = 0; index < componentMasks.Length; index++)
|
||||||
{
|
{
|
||||||
_componentMasks[index] = componentMasks[index];
|
_componentMasks |= componentMasks[index] << (index * 4);
|
||||||
|
|
||||||
RestoreComponentMask(index);
|
RestoreComponentMask(index, force: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1436,18 +1448,34 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RestoreComponentMask(int index)
|
public void RestoreComponentMask(int index, bool force = true)
|
||||||
{
|
{
|
||||||
// If the bound render target is bgra, swap the red and blue masks.
|
// If the bound render target is bgra, swap the red and blue masks.
|
||||||
uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u;
|
uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u;
|
||||||
uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u;
|
uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u;
|
||||||
|
|
||||||
|
int shift = index * 4;
|
||||||
|
uint componentMask = _componentMasks & _fragmentOutputMap;
|
||||||
|
uint checkMask = 0xfu << shift;
|
||||||
|
uint componentMaskAtIndex = componentMask & checkMask;
|
||||||
|
|
||||||
|
if (!force && componentMaskAtIndex == (_currentComponentMasks & checkMask))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentMask >>= shift;
|
||||||
|
componentMask &= 0xfu;
|
||||||
|
|
||||||
GL.ColorMask(
|
GL.ColorMask(
|
||||||
index,
|
index,
|
||||||
(_componentMasks[index] & redMask) != 0,
|
(componentMask & redMask) != 0,
|
||||||
(_componentMasks[index] & 2u) != 0,
|
(componentMask & 2u) != 0,
|
||||||
(_componentMasks[index] & blueMask) != 0,
|
(componentMask & blueMask) != 0,
|
||||||
(_componentMasks[index] & 8u) != 0);
|
(componentMask & 8u) != 0);
|
||||||
|
|
||||||
|
_currentComponentMasks &= ~checkMask;
|
||||||
|
_currentComponentMasks |= componentMaskAtIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RestoreScissor0Enable()
|
public void RestoreScissor0Enable()
|
||||||
|
@@ -1,11 +1,8 @@
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.OpenGL
|
namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
@@ -29,7 +26,10 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
|
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
|
||||||
private IShader[] _shaders;
|
private IShader[] _shaders;
|
||||||
|
|
||||||
public Program(IShader[] shaders)
|
public bool HasFragmentShader;
|
||||||
|
public int FragmentOutputMap { get; }
|
||||||
|
|
||||||
|
public Program(IShader[] shaders, int fragmentOutputMap)
|
||||||
{
|
{
|
||||||
Handle = GL.CreateProgram();
|
Handle = GL.CreateProgram();
|
||||||
|
|
||||||
@@ -37,17 +37,23 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
|
|
||||||
for (int index = 0; index < shaders.Length; index++)
|
for (int index = 0; index < shaders.Length; index++)
|
||||||
{
|
{
|
||||||
int shaderHandle = ((Shader)shaders[index]).Handle;
|
Shader shader = (Shader)shaders[index];
|
||||||
|
|
||||||
GL.AttachShader(Handle, shaderHandle);
|
if (shader.IsFragment)
|
||||||
|
{
|
||||||
|
HasFragmentShader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL.AttachShader(Handle, shader.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
GL.LinkProgram(Handle);
|
GL.LinkProgram(Handle);
|
||||||
|
|
||||||
_shaders = shaders;
|
_shaders = shaders;
|
||||||
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Program(ReadOnlySpan<byte> code)
|
public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
|
||||||
{
|
{
|
||||||
BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
|
BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
|
||||||
|
|
||||||
@@ -60,6 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
|
GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HasFragmentShader = hasFragmentShader;
|
||||||
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind()
|
public void Bind()
|
||||||
|
@@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
|||||||
|
|
||||||
public Counters()
|
public Counters()
|
||||||
{
|
{
|
||||||
int count = Enum.GetNames(typeof(CounterType)).Length;
|
int count = Enum.GetNames<CounterType>().Length;
|
||||||
|
|
||||||
_counterQueues = new CounterQueue[count];
|
_counterQueues = new CounterQueue[count];
|
||||||
}
|
}
|
||||||
|
@@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
return Buffer.Create(size);
|
return Buffer.Create(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram CreateProgram(IShader[] shaders)
|
public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
|
||||||
{
|
{
|
||||||
return new Program(shaders);
|
return new Program(shaders, info.FragmentOutputMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISampler CreateSampler(SamplerCreateInfo info)
|
public ISampler CreateSampler(SamplerCreateInfo info)
|
||||||
@@ -202,9 +202,9 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_sync.Dispose();
|
_sync.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IProgram LoadProgramBinary(byte[] programBinary)
|
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
|
||||||
{
|
{
|
||||||
return new Program(programBinary);
|
return new Program(programBinary, hasFragmentShader, info.FragmentOutputMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateSync(ulong id)
|
public void CreateSync(ulong id)
|
||||||
|
@@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
class Shader : IShader
|
class Shader : IShader
|
||||||
{
|
{
|
||||||
public int Handle { get; private set; }
|
public int Handle { get; private set; }
|
||||||
|
public bool IsFragment { get; }
|
||||||
|
|
||||||
public Shader(ShaderStage stage, string code)
|
public Shader(ShaderStage stage, string code)
|
||||||
{
|
{
|
||||||
@@ -22,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
};
|
};
|
||||||
|
|
||||||
Handle = GL.CreateShader(type);
|
Handle = GL.CreateShader(type);
|
||||||
|
IsFragment = stage == ShaderStage.Fragment;
|
||||||
|
|
||||||
GL.ShaderSource(Handle, code);
|
GL.ShaderSource(Handle, code);
|
||||||
GL.CompileShader(Handle);
|
GL.CompileShader(Handle);
|
||||||
|
@@ -5,32 +5,35 @@ namespace Ryujinx.Graphics.Shader
|
|||||||
{
|
{
|
||||||
public class ShaderProgramInfo
|
public class ShaderProgramInfo
|
||||||
{
|
{
|
||||||
public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
|
public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
|
||||||
public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
|
public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
|
||||||
public ReadOnlyCollection<TextureDescriptor> Textures { get; }
|
public ReadOnlyCollection<TextureDescriptor> Textures { get; }
|
||||||
public ReadOnlyCollection<TextureDescriptor> Images { get; }
|
public ReadOnlyCollection<TextureDescriptor> Images { get; }
|
||||||
|
|
||||||
public bool UsesInstanceId { get; }
|
public bool UsesInstanceId { get; }
|
||||||
public bool UsesRtLayer { get; }
|
public bool UsesRtLayer { get; }
|
||||||
public byte ClipDistancesWritten { get; }
|
public byte ClipDistancesWritten { get; }
|
||||||
|
public int FragmentOutputMap { get; }
|
||||||
|
|
||||||
public ShaderProgramInfo(
|
public ShaderProgramInfo(
|
||||||
BufferDescriptor[] cBuffers,
|
BufferDescriptor[] cBuffers,
|
||||||
BufferDescriptor[] sBuffers,
|
BufferDescriptor[] sBuffers,
|
||||||
TextureDescriptor[] textures,
|
TextureDescriptor[] textures,
|
||||||
TextureDescriptor[] images,
|
TextureDescriptor[] images,
|
||||||
bool usesInstanceId,
|
bool usesInstanceId,
|
||||||
bool usesRtLayer,
|
bool usesRtLayer,
|
||||||
byte clipDistancesWritten)
|
byte clipDistancesWritten,
|
||||||
|
int fragmentOutputMap)
|
||||||
{
|
{
|
||||||
CBuffers = Array.AsReadOnly(cBuffers);
|
CBuffers = Array.AsReadOnly(cBuffers);
|
||||||
SBuffers = Array.AsReadOnly(sBuffers);
|
SBuffers = Array.AsReadOnly(sBuffers);
|
||||||
Textures = Array.AsReadOnly(textures);
|
Textures = Array.AsReadOnly(textures);
|
||||||
Images = Array.AsReadOnly(images);
|
Images = Array.AsReadOnly(images);
|
||||||
|
|
||||||
UsesInstanceId = usesInstanceId;
|
UsesInstanceId = usesInstanceId;
|
||||||
UsesRtLayer = usesRtLayer;
|
UsesRtLayer = usesRtLayer;
|
||||||
ClipDistancesWritten = clipDistancesWritten;
|
ClipDistancesWritten = clipDistancesWritten;
|
||||||
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -172,11 +172,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
|
for (int rtIndex = 0; rtIndex < 8; rtIndex++)
|
||||||
{
|
{
|
||||||
OmapTarget target = Config.OmapTargets[rtIndex];
|
|
||||||
|
|
||||||
for (int component = 0; component < 4; component++)
|
for (int component = 0; component < 4; component++)
|
||||||
{
|
{
|
||||||
if (!target.ComponentEnabled(component))
|
bool componentEnabled = (Config.OmapTargets & (1 << (rtIndex * 4 + component))) != 0;
|
||||||
|
if (!componentEnabled)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -210,7 +209,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.Enabled)
|
bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
|
||||||
|
if (targetEnabled)
|
||||||
{
|
{
|
||||||
Config.SetOutputUserAttribute(rtIndex, perPatch: false);
|
Config.SetOutputUserAttribute(rtIndex, perPatch: false);
|
||||||
regIndexBase += 4;
|
regIndexBase += 4;
|
||||||
|
@@ -25,9 +25,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public ImapPixelType[] ImapTypes { get; }
|
public ImapPixelType[] ImapTypes { get; }
|
||||||
|
|
||||||
public OmapTarget[] OmapTargets { get; }
|
public int OmapTargets { get; }
|
||||||
public bool OmapSampleMask { get; }
|
public bool OmapSampleMask { get; }
|
||||||
public bool OmapDepth { get; }
|
public bool OmapDepth { get; }
|
||||||
|
|
||||||
public IGpuAccessor GpuAccessor { get; }
|
public IGpuAccessor GpuAccessor { get; }
|
||||||
|
|
||||||
@@ -135,21 +135,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
public int GetDepthRegister()
|
public int GetDepthRegister()
|
||||||
{
|
{
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for (int index = 0; index < OmapTargets.Length; index++)
|
|
||||||
{
|
|
||||||
for (int component = 0; component < 4; component++)
|
|
||||||
{
|
|
||||||
if (OmapTargets[index].ComponentEnabled(component))
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The depth register is always two registers after the last color output.
|
// The depth register is always two registers after the last color output.
|
||||||
return count + 1;
|
return BitOperations.PopCount((uint)OmapTargets) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)
|
public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)
|
||||||
|
@@ -36,37 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OmapTarget
|
|
||||||
{
|
|
||||||
public bool Red { get; }
|
|
||||||
public bool Green { get; }
|
|
||||||
public bool Blue { get; }
|
|
||||||
public bool Alpha { get; }
|
|
||||||
|
|
||||||
public bool Enabled => Red || Green || Blue || Alpha;
|
|
||||||
|
|
||||||
public OmapTarget(bool red, bool green, bool blue, bool alpha)
|
|
||||||
{
|
|
||||||
Red = red;
|
|
||||||
Green = green;
|
|
||||||
Blue = blue;
|
|
||||||
Alpha = alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ComponentEnabled(int component)
|
|
||||||
{
|
|
||||||
switch (component)
|
|
||||||
{
|
|
||||||
case 0: return Red;
|
|
||||||
case 1: return Green;
|
|
||||||
case 2: return Blue;
|
|
||||||
case 3: return Alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(component));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ShaderHeader
|
class ShaderHeader
|
||||||
{
|
{
|
||||||
public int SphType { get; }
|
public int SphType { get; }
|
||||||
@@ -85,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public bool GpPassthrough { get; }
|
public bool GpPassthrough { get; }
|
||||||
|
|
||||||
public bool DoesLoadOrStore { get; }
|
public bool DoesLoadOrStore { get; }
|
||||||
public bool DoesFp64 { get; }
|
public bool DoesFp64 { get; }
|
||||||
|
|
||||||
public int StreamOutMask { get; }
|
public int StreamOutMask { get; }
|
||||||
|
|
||||||
@@ -104,13 +73,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
public int MaxOutputVertexCount { get; }
|
public int MaxOutputVertexCount { get; }
|
||||||
|
|
||||||
public int StoreReqStart { get; }
|
public int StoreReqStart { get; }
|
||||||
public int StoreReqEnd { get; }
|
public int StoreReqEnd { get; }
|
||||||
|
|
||||||
public ImapPixelType[] ImapTypes { get; }
|
public ImapPixelType[] ImapTypes { get; }
|
||||||
|
|
||||||
public OmapTarget[] OmapTargets { get; }
|
public int OmapTargets { get; }
|
||||||
public bool OmapSampleMask { get; }
|
public bool OmapSampleMask { get; }
|
||||||
public bool OmapDepth { get; }
|
public bool OmapDepth { get; }
|
||||||
|
|
||||||
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
|
public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
|
||||||
{
|
{
|
||||||
@@ -144,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
GpPassthrough = commonWord0.Extract(24);
|
GpPassthrough = commonWord0.Extract(24);
|
||||||
|
|
||||||
DoesLoadOrStore = commonWord0.Extract(26);
|
DoesLoadOrStore = commonWord0.Extract(26);
|
||||||
DoesFp64 = commonWord0.Extract(27);
|
DoesFp64 = commonWord0.Extract(27);
|
||||||
|
|
||||||
StreamOutMask = commonWord0.Extract(28, 4);
|
StreamOutMask = commonWord0.Extract(28, 4);
|
||||||
|
|
||||||
@@ -163,7 +132,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
MaxOutputVertexCount = commonWord4.Extract(0, 12);
|
MaxOutputVertexCount = commonWord4.Extract(0, 12);
|
||||||
|
|
||||||
StoreReqStart = commonWord4.Extract(12, 8);
|
StoreReqStart = commonWord4.Extract(12, 8);
|
||||||
StoreReqEnd = commonWord4.Extract(24, 8);
|
StoreReqEnd = commonWord4.Extract(24, 8);
|
||||||
|
|
||||||
ImapTypes = new ImapPixelType[32];
|
ImapTypes = new ImapPixelType[32];
|
||||||
|
|
||||||
@@ -179,21 +148,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
}
|
}
|
||||||
|
|
||||||
int type2OmapTarget = header[18];
|
int type2OmapTarget = header[18];
|
||||||
int type2Omap = header[19];
|
int type2Omap = header[19];
|
||||||
|
|
||||||
OmapTargets = new OmapTarget[8];
|
|
||||||
|
|
||||||
for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4)
|
|
||||||
{
|
|
||||||
OmapTargets[offset >> 2] = new OmapTarget(
|
|
||||||
type2OmapTarget.Extract(offset + 0),
|
|
||||||
type2OmapTarget.Extract(offset + 1),
|
|
||||||
type2OmapTarget.Extract(offset + 2),
|
|
||||||
type2OmapTarget.Extract(offset + 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
OmapTargets = type2OmapTarget;
|
||||||
OmapSampleMask = type2Omap.Extract(0);
|
OmapSampleMask = type2Omap.Extract(0);
|
||||||
OmapDepth = type2Omap.Extract(1);
|
OmapDepth = type2Omap.Extract(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -105,7 +105,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
config.GetImageDescriptors(),
|
config.GetImageDescriptors(),
|
||||||
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
|
||||||
config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
|
||||||
config.ClipDistancesWritten);
|
config.ClipDistancesWritten,
|
||||||
|
config.OmapTargets);
|
||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||||
|
|
||||||
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
|
foreach (StorageId storageId in Enum.GetValues<StorageId>())
|
||||||
{
|
{
|
||||||
string contentDirectory = null;
|
string contentDirectory = null;
|
||||||
string contentPathString = null;
|
string contentPathString = null;
|
||||||
|
@@ -433,7 +433,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
|
|
||||||
generator.Emit(OpCodes.Ret);
|
generator.Emit(OpCodes.Ret);
|
||||||
|
|
||||||
return (Action<T, ExecutionContext>)method.CreateDelegate(typeof(Action<T, ExecutionContext>));
|
return method.CreateDelegate<Action<T, ExecutionContext>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckIfTypeIsSupported(Type type, string svcName)
|
private static void CheckIfTypeIsSupported(Type type, string svcName)
|
||||||
|
@@ -1021,7 +1021,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
|
|
||||||
HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None;
|
HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None;
|
||||||
|
|
||||||
if (Enum.IsDefined(typeof(NpadStyleIndex), deviceType))
|
if (Enum.IsDefined<NpadStyleIndex>(deviceType))
|
||||||
{
|
{
|
||||||
vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator;
|
vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator;
|
||||||
}
|
}
|
||||||
|
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.SystemState
|
|||||||
SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese,
|
SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese,
|
||||||
SystemLanguage.Chinese or
|
SystemLanguage.Chinese or
|
||||||
SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
|
SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
|
||||||
_ => Enum.Parse<TitleLanguage>(Enum.GetName(typeof(SystemLanguage), language)),
|
_ => Enum.Parse<TitleLanguage>(Enum.GetName<SystemLanguage>(language)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -391,24 +391,29 @@ namespace Ryujinx.Input.HLE
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
|
private static JoystickPosition ApplyDeadzone(float x, float y, float deadzone)
|
||||||
{
|
{
|
||||||
return new JoystickPosition
|
float magnitudeClamped = Math.Min(MathF.Sqrt(x * x + y * y), 1f);
|
||||||
|
|
||||||
|
if (magnitudeClamped <= deadzone)
|
||||||
{
|
{
|
||||||
Dx = ClampAxis(MathF.Abs(x) > deadzone ? x : 0.0f),
|
return new JoystickPosition() {Dx = 0, Dy = 0};
|
||||||
Dy = ClampAxis(MathF.Abs(y) > deadzone ? y : 0.0f)
|
}
|
||||||
|
|
||||||
|
return new JoystickPosition()
|
||||||
|
{
|
||||||
|
Dx = ClampAxis((x / magnitudeClamped) * ((magnitudeClamped - deadzone) / (1 - deadzone))),
|
||||||
|
Dy = ClampAxis((y / magnitudeClamped) * ((magnitudeClamped - deadzone) / (1 - deadzone)))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static short ClampAxis(float value)
|
private static short ClampAxis(float value)
|
||||||
{
|
{
|
||||||
if (value <= -short.MaxValue)
|
if (Math.Sign(value) < 0)
|
||||||
{
|
{
|
||||||
return -short.MaxValue;
|
return (short)Math.Max(value * -short.MinValue, short.MinValue);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (short)(value * short.MaxValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (short)Math.Min(value * short.MaxValue, short.MaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
@@ -27,8 +27,8 @@ namespace Ryujinx.Input.Motion.CemuHook
|
|||||||
private readonly Dictionary<int, Dictionary<int, MotionInput>> _motionData;
|
private readonly Dictionary<int, Dictionary<int, MotionInput>> _motionData;
|
||||||
private readonly Dictionary<int, UdpClient> _clients;
|
private readonly Dictionary<int, UdpClient> _clients;
|
||||||
|
|
||||||
private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues(typeof(PlayerIndex)).Length];
|
private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues<PlayerIndex>().Length];
|
||||||
private readonly long[] _clientRetryTimer = new long[Enum.GetValues(typeof(PlayerIndex)).Length];
|
private readonly long[] _clientRetryTimer = new long[Enum.GetValues<PlayerIndex>().Length];
|
||||||
private NpadManager _npadManager;
|
private NpadManager _npadManager;
|
||||||
|
|
||||||
public Client(NpadManager npadManager)
|
public Client(NpadManager npadManager)
|
||||||
|
@@ -58,7 +58,7 @@ namespace Ryujinx.Configuration
|
|||||||
{
|
{
|
||||||
bool noFilter = e.NewValue.Length == 0;
|
bool noFilter = e.NewValue.Length == 0;
|
||||||
|
|
||||||
foreach (var logClass in EnumExtensions.GetValues<LogClass>())
|
foreach (var logClass in Enum.GetValues<LogClass>())
|
||||||
{
|
{
|
||||||
Logger.SetEnable(logClass, noFilter);
|
Logger.SetEnable(logClass, noFilter);
|
||||||
}
|
}
|
||||||
|
@@ -150,7 +150,7 @@ namespace Ryujinx.Input.GTK3
|
|||||||
|
|
||||||
static GTK3MappingHelper()
|
static GTK3MappingHelper()
|
||||||
{
|
{
|
||||||
var inputKeys = Enum.GetValues(typeof(Key));
|
var inputKeys = Enum.GetValues<Key>();
|
||||||
|
|
||||||
// GtkKey is not contiguous and quite large, so use a dictionary instead of an array.
|
// GtkKey is not contiguous and quite large, so use a dictionary instead of an array.
|
||||||
_gtkKeyMapping = new Dictionary<GtkKey, Key>();
|
_gtkKeyMapping = new Dictionary<GtkKey, Key>();
|
||||||
|
@@ -1209,7 +1209,7 @@ namespace Ryujinx.Ui
|
|||||||
{
|
{
|
||||||
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value;
|
||||||
|
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Value = ((int)aspectRatio + 1) > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
ConfigurationState.Instance.Graphics.AspectRatio.Value = ((int)aspectRatio + 1) > Enum.GetNames<AspectRatio>().Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Row_Clicked(object sender, ButtonReleaseEventArgs args)
|
private void Row_Clicked(object sender, ButtonReleaseEventArgs args)
|
||||||
|
@@ -181,7 +181,7 @@ namespace Ryujinx.Ui.Windows
|
|||||||
_fsAccessLogToggle.Click();
|
_fsAccessLogToggle.Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (GraphicsDebugLevel level in Enum.GetValues(typeof(GraphicsDebugLevel)))
|
foreach (GraphicsDebugLevel level in Enum.GetValues<GraphicsDebugLevel>())
|
||||||
{
|
{
|
||||||
_graphicsDebugLevel.Append(level.ToString(), level.ToString());
|
_graphicsDebugLevel.Append(level.ToString(), level.ToString());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user