Compare commits

..

5 Commits

Author SHA1 Message Date
jcm
f61b7818c3 Avalonia: Add macOS check for Color Space Passthrough (#5754)
* add macOS check for color passthrough

* use existing IsMacOS property

---------

Co-authored-by: jcm <butt@butts.com>
2023-10-04 19:15:37 +02:00
gdkchan
a2a97e1b11 Implement textureSamples texture query shader instruction (#5750)
* Implement textureSamples texture query shader instruction

* Shader cache version bump
2023-10-03 22:43:11 +00:00
gdkchan
8b2625b0be Decrement nvmap reference count on surface flinger prealloc (#5753) 2023-10-02 22:13:29 +00:00
gdkchan
651e24fed9 Signal friends completion event and stub CheckBlockedUserListAvailability (#5743) 2023-09-29 13:24:44 +02:00
gdkchan
41b104d0fb Fix audio renderer compressor effect (#5742)
* Delete DecibelToLinearExtended and fix Log10 function

* Fix CopyBuffer and ClearBuffer

* Change effect states from class to struct + formatting

* Formatting

* Make UpdateLowPassFilter readonly

* More compressor fixes
2023-09-29 10:48:49 +00:00
29 changed files with 303 additions and 136 deletions

View File

@@ -31,9 +31,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public bool IsEffectEnabled { get; } public bool IsEffectEnabled { get; }
public AuxiliaryBufferCommand(uint bufferOffset, byte inputBufferOffset, byte outputBufferOffset, public AuxiliaryBufferCommand(
ref AuxiliaryBufferAddresses sendBufferInfo, bool isEnabled, uint countMax, uint bufferOffset,
CpuAddress outputBuffer, CpuAddress inputBuffer, uint updateCount, uint writeOffset, int nodeId) byte inputBufferOffset,
byte outputBufferOffset,
ref AuxiliaryBufferAddresses sendBufferInfo,
bool isEnabled,
uint countMax,
CpuAddress outputBuffer,
CpuAddress inputBuffer,
uint updateCount,
uint writeOffset,
int nodeId)
{ {
Enabled = true; Enabled = true;
NodeId = nodeId; NodeId = nodeId;

View File

@@ -21,7 +21,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private BiquadFilterParameter _parameter; private BiquadFilterParameter _parameter;
public BiquadFilterCommand(int baseIndex, ref BiquadFilterParameter filter, Memory<BiquadFilterState> biquadFilterStateMemory, int inputBufferOffset, int outputBufferOffset, bool needInitialization, int nodeId) public BiquadFilterCommand(
int baseIndex,
ref BiquadFilterParameter filter,
Memory<BiquadFilterState> biquadFilterStateMemory,
int inputBufferOffset,
int outputBufferOffset,
bool needInitialization,
int nodeId)
{ {
_parameter = filter; _parameter = filter;
BiquadFilterState = biquadFilterStateMemory; BiquadFilterState = biquadFilterStateMemory;

View File

@@ -77,7 +77,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void ClearBuffer(int index) public unsafe void ClearBuffer(int index)
{ {
Unsafe.InitBlock((void*)GetBufferPointer(index), 0, SampleCount); Unsafe.InitBlock((void*)GetBufferPointer(index), 0, SampleCount * sizeof(float));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -89,7 +89,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void CopyBuffer(int outputBufferIndex, int inputBufferIndex) public unsafe void CopyBuffer(int outputBufferIndex, int inputBufferIndex)
{ {
Unsafe.CopyBlock((void*)GetBufferPointer(outputBufferIndex), (void*)GetBufferPointer(inputBufferIndex), SampleCount); Unsafe.CopyBlock((void*)GetBufferPointer(outputBufferIndex), (void*)GetBufferPointer(inputBufferIndex), SampleCount * sizeof(float));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -94,18 +94,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain); float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
float y = FloatingPointHelper.Log10(newMean) * 10.0f; float y = FloatingPointHelper.Log10(newMean) * 10.0f;
float z = 0.0f; float z = 1.0f;
bool unknown10OutOfRange = false; bool unknown10OutOfRange = y >= state.Unknown10;
if (newMean < 1.0e-10f) if (newMean < 1.0e-10f)
{ {
z = 1.0f; y = -100.0f;
unknown10OutOfRange = state.Unknown10 < -100.0f; unknown10OutOfRange = state.Unknown10 <= -100.0f;
} }
if (y >= state.Unknown10 || unknown10OutOfRange) if (unknown10OutOfRange)
{ {
float tmpGain; float tmpGain;
@@ -118,7 +118,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction); tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
} }
z = FloatingPointHelper.DecibelToLinearExtended(tmpGain); z = FloatingPointHelper.DecibelToLinear(tmpGain);
} }
float unknown4New = z; float unknown4New = z;

View File

@@ -28,7 +28,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private LimiterParameter _parameter; private LimiterParameter _parameter;
public LimiterCommandVersion2(uint bufferOffset, LimiterParameter parameter, Memory<LimiterState> state, Memory<EffectResultState> resultState, bool isEnabled, ulong workBuffer, int nodeId) public LimiterCommandVersion2(
uint bufferOffset,
LimiterParameter parameter,
Memory<LimiterState> state,
Memory<EffectResultState> resultState,
bool isEnabled,
ulong workBuffer,
int nodeId)
{ {
Enabled = true; Enabled = true;
NodeId = nodeId; NodeId = nodeId;

View File

@@ -79,7 +79,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbMono(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
ref state,
outputBuffers, outputBuffers,
inputBuffers, inputBuffers,
sampleCount, sampleCount,
@@ -92,7 +93,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbStereo(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
ref state,
outputBuffers, outputBuffers,
inputBuffers, inputBuffers,
sampleCount, sampleCount,
@@ -105,7 +107,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbQuadraphonic(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
ref state,
outputBuffers, outputBuffers,
inputBuffers, inputBuffers,
sampleCount, sampleCount,
@@ -118,7 +121,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount) private void ProcessReverbSurround(ref ReverbState state, ReadOnlySpan<IntPtr> outputBuffers, ReadOnlySpan<IntPtr> inputBuffers, uint sampleCount)
{ {
ProcessReverbGeneric(ref state, ProcessReverbGeneric(
ref state,
outputBuffers, outputBuffers,
inputBuffers, inputBuffers,
sampleCount, sampleCount,

View File

@@ -52,7 +52,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
{ {
// NOTE: Nintendo uses an approximation of log10, we don't. // NOTE: Nintendo uses an approximation of log10, we don't.
// As such, we support the same ranges as Nintendo to avoid unexpected behaviours. // As such, we support the same ranges as Nintendo to avoid unexpected behaviours.
return MathF.Pow(10, MathF.Max(x, 1.0e-10f)); return MathF.Log10(MathF.Max(x, 1.0e-10f));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -62,7 +62,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
foreach (float input in inputs) foreach (float input in inputs)
{ {
res += (input * input); float normInput = input * (1f / 32768f);
res += normInput * normInput;
} }
res /= inputs.Length; res /= inputs.Length;
@@ -81,19 +82,6 @@ namespace Ryujinx.Audio.Renderer.Dsp
return MathF.Pow(10.0f, db / 20.0f); return MathF.Pow(10.0f, db / 20.0f);
} }
/// <summary>
/// Map decibel to linear in [0, 2] range.
/// </summary>
/// <param name="db">The decibel value to convert</param>
/// <returns>Converted linear value in [0, 2] range</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DecibelToLinearExtended(float db)
{
float tmp = MathF.Log2(DecibelToLinear(db));
return MathF.Truncate(tmp) + MathF.Pow(2.0f, tmp - MathF.Truncate(tmp));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DegreesToRadians(float degrees) public static float DegreesToRadians(float degrees)
{ {

View File

@@ -3,7 +3,7 @@ using Ryujinx.Audio.Renderer.Parameter.Effect;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class CompressorState public struct CompressorState
{ {
public ExponentialMovingAverage InputMovingAverage; public ExponentialMovingAverage InputMovingAverage;
public float Unknown4; public float Unknown4;
@@ -45,7 +45,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax; CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax;
Unknown10 = threshold - 1.5f; Unknown10 = threshold - 1.5f;
Unknown14 = threshold + 1.5f; Unknown14 = threshold + 1.5f;
OutputGain = FloatingPointHelper.DecibelToLinearExtended(parameter.OutputGain + makeupGain); OutputGain = FloatingPointHelper.DecibelToLinear(parameter.OutputGain + makeupGain);
} }
} }
} }

View File

@@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class DelayState public struct DelayState
{ {
public DelayLine[] DelayLines { get; } public DelayLine[] DelayLines { get; }
public float[] LowPassZ { get; set; } public float[] LowPassZ { get; set; }
@@ -53,7 +53,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
LowPassBaseGain = 1.0f - LowPassFeedbackGain; LowPassBaseGain = 1.0f - LowPassFeedbackGain;
} }
public void UpdateLowPassFilter(ref float tempRawRef, uint channelCount) public readonly void UpdateLowPassFilter(ref float tempRawRef, uint channelCount)
{ {
for (int i = 0; i < channelCount; i++) for (int i = 0; i < channelCount; i++)
{ {

View File

@@ -4,7 +4,7 @@ using System;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class LimiterState public struct LimiterState
{ {
public ExponentialMovingAverage[] DetectorAverage; public ExponentialMovingAverage[] DetectorAverage;
public ExponentialMovingAverage[] CompressionGainAverage; public ExponentialMovingAverage[] CompressionGainAverage;

View File

@@ -4,7 +4,7 @@ using System;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class Reverb3dState public struct Reverb3dState
{ {
private readonly float[] _fdnDelayMinTimes = new float[4] { 5.0f, 6.0f, 13.0f, 14.0f }; private readonly float[] _fdnDelayMinTimes = new float[4] { 5.0f, 6.0f, 13.0f, 14.0f };
private readonly float[] _fdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f }; private readonly float[] _fdnDelayMaxTimes = new float[4] { 45.704f, 82.782f, 149.94f, 271.58f };

View File

@@ -5,7 +5,7 @@ using System;
namespace Ryujinx.Audio.Renderer.Dsp.State namespace Ryujinx.Audio.Renderer.Dsp.State
{ {
public class ReverbState public struct ReverbState
{ {
private static readonly float[] _fdnDelayTimes = new float[20] private static readonly float[] _fdnDelayTimes = new float[20]
{ {

View File

@@ -147,6 +147,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableTextureRecompression { get; set; } public bool EnableTextureRecompression { get; set; }
public bool EnableMacroHLE { get; set; } public bool EnableMacroHLE { get; set; }
public bool EnableColorSpacePassthrough { get; set; } public bool EnableColorSpacePassthrough { get; set; }
public bool ColorSpacePassthroughAvailable => IsMacOS;
public bool EnableFileLog { get; set; } public bool EnableFileLog { get; set; }
public bool EnableStub { get; set; } public bool EnableStub { get; set; }
public bool EnableInfo { get; set; } public bool EnableInfo { get; set; }

View File

@@ -73,6 +73,7 @@
<TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" /> <TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" />
</CheckBox> </CheckBox>
<CheckBox IsChecked="{Binding EnableColorSpacePassthrough}" <CheckBox IsChecked="{Binding EnableColorSpacePassthrough}"
IsVisible="{Binding ColorSpacePassthroughAvailable}"
ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}"> ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}">
<TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" /> <TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" />
</CheckBox> </CheckBox>

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 5682; private const uint CodeGenVersion = 5750;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View File

@@ -184,8 +184,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.TextureSample: case Instruction.TextureSample:
return TextureSample(context, operation); return TextureSample(context, operation);
case Instruction.TextureSize: case Instruction.TextureQuerySamples:
return TextureSize(context, operation); return TextureQuerySamples(context, operation);
case Instruction.TextureQuerySize:
return TextureQuerySize(context, operation);
case Instruction.UnpackDouble2x32: case Instruction.UnpackDouble2x32:
return UnpackDouble2x32(context, operation); return UnpackDouble2x32(context, operation);

View File

@@ -118,7 +118,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.Subtract, InstType.OpBinary, "-", 2); Add(Instruction.Subtract, InstType.OpBinary, "-", 2);
Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd); Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd);
Add(Instruction.TextureSample, InstType.Special); Add(Instruction.TextureSample, InstType.Special);
Add(Instruction.TextureSize, InstType.Special); Add(Instruction.TextureQuerySamples, InstType.Special);
Add(Instruction.TextureQuerySize, InstType.Special);
Add(Instruction.Truncate, InstType.CallUnary, "trunc"); Add(Instruction.Truncate, InstType.CallUnary, "trunc");
Add(Instruction.UnpackDouble2x32, InstType.Special); Add(Instruction.UnpackDouble2x32, InstType.Special);
Add(Instruction.UnpackHalf2x16, InstType.Special); Add(Instruction.UnpackHalf2x16, InstType.Special);

View File

@@ -517,7 +517,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return texCall; return texCall;
} }
public static string TextureSize(CodeGenContext context, AstOperation operation) public static string TextureQuerySamples(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatInt(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null;
if (isIndexed)
{
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
return $"textureSamples({samplerName})";
}
public static string TextureQuerySize(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;

View File

@@ -134,7 +134,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.Subtract, GenerateSubtract); Add(Instruction.Subtract, GenerateSubtract);
Add(Instruction.SwizzleAdd, GenerateSwizzleAdd); Add(Instruction.SwizzleAdd, GenerateSwizzleAdd);
Add(Instruction.TextureSample, GenerateTextureSample); Add(Instruction.TextureSample, GenerateTextureSample);
Add(Instruction.TextureSize, GenerateTextureSize); Add(Instruction.TextureQuerySamples, GenerateTextureQuerySamples);
Add(Instruction.TextureQuerySize, GenerateTextureQuerySize);
Add(Instruction.Truncate, GenerateTruncate); Add(Instruction.Truncate, GenerateTruncate);
Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32); Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32);
Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16); Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16);
@@ -1492,7 +1493,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return new OperationResult(swizzledResultType, result); return new OperationResult(swizzledResultType, result);
} }
private static OperationResult GenerateTextureSize(CodeGenContext context, AstOperation operation) private static OperationResult GenerateTextureQuerySamples(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return new OperationResult(AggregateType.S32, context.Constant(context.TypeS32(), 0));
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
if (isIndexed)
{
context.GetS32(texOp.GetSource(0));
}
(var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
var image = context.Load(sampledImageType, sampledImageVariable);
image = context.Image(imageType, image);
SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image);
return new OperationResult(AggregateType.S32, result);
}
private static OperationResult GenerateTextureQuerySize(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;

View File

@@ -1093,18 +1093,29 @@ namespace Ryujinx.Graphics.Shader.Instructions
SamplerType type; SamplerType type;
if (isBindless) if (isBindless)
{
if (query == TexQuery.TexHeaderTextureType)
{
type = SamplerType.Texture2D | SamplerType.Multisample;
}
else
{ {
type = (componentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D; type = (componentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D;
} }
}
else else
{ {
type = context.TranslatorContext.GpuAccessor.QuerySamplerType(imm); type = context.TranslatorContext.GpuAccessor.QuerySamplerType(imm);
} }
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None; TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
int binding;
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( switch (query)
Instruction.TextureSize, {
case TexQuery.TexHeaderDimension:
binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
Instruction.TextureQuerySize,
type, type,
TextureFormat.Unknown, TextureFormat.Unknown,
flags, flags,
@@ -1122,12 +1133,46 @@ namespace Ryujinx.Graphics.Shader.Instructions
break; break;
} }
// TODO: Validate and use query parameter. context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources));
Operand res = context.TextureSize(type, flags, binding, compIndex, sources);
context.Copy(d, res);
} }
} }
break;
case TexQuery.TexHeaderTextureType:
binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
Instruction.TextureQuerySamples,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
if ((componentMask & 4) != 0)
{
// Skip first 2 components if necessary.
if ((componentMask & 1) != 0)
{
GetDest();
}
if ((componentMask & 2) != 0)
{
GetDest();
}
Operand d = GetDest();
if (d != null)
{
context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources));
}
}
break;
default:
context.TranslatorContext.GpuAccessor.Log($"Invalid or unsupported query type \"{query}\".");
break;
}
} }
private static void EmitTextureSample( private static void EmitTextureSample(

View File

@@ -1,10 +1,8 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{ {
[Flags] [Flags]
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
enum Instruction enum Instruction
{ {
Absolute = 1, Absolute = 1,
@@ -118,7 +116,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Subtract, Subtract,
SwizzleAdd, SwizzleAdd,
TextureSample, TextureSample,
TextureSize, TextureQuerySamples,
TextureQuerySize,
Truncate, Truncate,
UnpackDouble2x32, UnpackDouble2x32,
UnpackHalf2x16, UnpackHalf2x16,
@@ -160,7 +159,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public static bool IsTextureQuery(this Instruction inst) public static bool IsTextureQuery(this Instruction inst)
{ {
inst &= Instruction.Mask; inst &= Instruction.Mask;
return inst == Instruction.Lod || inst == Instruction.TextureSize; return inst == Instruction.Lod || inst == Instruction.TextureQuerySamples || inst == Instruction.TextureQuerySize;
} }
} }
} }

View File

@@ -124,7 +124,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32); Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32);
Add(Instruction.TextureSample, AggregateType.FP32); Add(Instruction.TextureSample, AggregateType.FP32);
Add(Instruction.TextureSize, AggregateType.S32, AggregateType.S32, AggregateType.S32); Add(Instruction.TextureQuerySamples, AggregateType.S32, AggregateType.S32);
Add(Instruction.TextureQuerySize, AggregateType.S32, AggregateType.S32, AggregateType.S32);
Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64); Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64);
Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32); Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32);

View File

@@ -897,7 +897,21 @@ namespace Ryujinx.Graphics.Shader.Translation
context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources)); context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
} }
public static Operand TextureSize( public static Operand TextureQuerySamples(
this EmitterContext context,
SamplerType type,
TextureFlags flags,
int binding,
Operand[] sources)
{
Operand dest = Local();
context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources));
return dest;
}
public static Operand TextureQuerySize(
this EmitterContext context, this EmitterContext context,
SamplerType type, SamplerType type,
TextureFlags flags, TextureFlags flags,
@@ -907,7 +921,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
Operand dest = Local(); Operand dest = Local();
context.Add(new TextureOperation(Instruction.TextureSize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources)); context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
return dest; return dest;
} }

View File

@@ -27,9 +27,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue; continue;
} }
if (texOp.Inst == Instruction.Lod || if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())
texOp.Inst == Instruction.TextureSample ||
texOp.Inst == Instruction.TextureSize)
{ {
Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block); Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
@@ -40,7 +38,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// as long bindless elimination is successful and we know where the texture descriptor is located. // as long bindless elimination is successful and we know where the texture descriptor is located.
bool rewriteSamplerType = bool rewriteSamplerType =
texOp.Type == SamplerType.TextureBuffer || texOp.Type == SamplerType.TextureBuffer ||
texOp.Inst == Instruction.TextureSize; texOp.Inst == Instruction.TextureQuerySamples ||
texOp.Inst == Instruction.TextureQuerySize;
if (bindlessHandle.Type == OperandType.ConstantBuffer) if (bindlessHandle.Type == OperandType.ConstantBuffer)
{ {

View File

@@ -232,8 +232,8 @@ namespace Ryujinx.Graphics.Shader.Translation
inst &= Instruction.Mask; inst &= Instruction.Mask;
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic; bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic; bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
bool accurateType = inst != Instruction.Lod && inst != Instruction.TextureSize; bool accurateType = !inst.IsTextureQuery();
bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize; bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureQuerySize;
bool coherent = flags.HasFlag(TextureFlags.Coherent); bool coherent = flags.HasFlag(TextureFlags.Coherent);
if (!isImage) if (!isImage)

View File

@@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
{ {
node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage); node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage);
node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor); node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor);
node = InsertConstOffsets(node, context.ResourceManager, context.GpuAccessor); node = InsertConstOffsets(node, context.GpuAccessor, context.Stage);
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat()) if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
{ {
@@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
if (texOp.Inst == Instruction.TextureSize && if (texOp.Inst == Instruction.TextureQuerySize &&
texOp.Index < 2 && texOp.Index < 2 &&
!isBindless && !isBindless &&
!isIndexed && !isIndexed &&
@@ -190,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation( LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
@@ -259,7 +259,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
@@ -287,7 +287,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
return node; return node;
} }
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor) private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, IGpuAccessor gpuAccessor, ShaderStage stage)
{ {
// Non-constant texture offsets are not allowed (according to the spec), // Non-constant texture offsets are not allowed (according to the spec),
// however some GPUs does support that. // however some GPUs does support that.
@@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
sources.CopyTo(newSources, 0); sources.CopyTo(newSources, 0);
Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount); Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount, stage);
int destIndex = 0; int destIndex = 0;
@@ -502,7 +502,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
else else
{ {
Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount); Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount, stage);
for (int index = 0; index < coordsCount; index++) for (int index = 0; index < coordsCount; index++)
{ {
@@ -554,11 +554,16 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
TextureOperation texOp, TextureOperation texOp,
Operand[] lodSources, Operand[] lodSources,
Operand bindlessHandle, Operand bindlessHandle,
int coordsCount) int coordsCount,
ShaderStage stage)
{ {
Operand[] texSizes = new Operand[coordsCount]; Operand[] texSizes = new Operand[coordsCount];
Operand lod = Local(); Operand lod;
if (stage == ShaderStage.Fragment)
{
lod = Local();
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.Lod, Instruction.Lod,
@@ -569,6 +574,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
0, 0,
new[] { lod }, new[] { lod },
lodSources)); lodSources));
}
else
{
lod = Const(0);
}
for (int index = 0; index < coordsCount; index++) for (int index = 0; index < coordsCount; index++)
{ {
@@ -586,7 +596,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,

View File

@@ -36,6 +36,8 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
throw new InvalidOperationException("Out of handles!"); throw new InvalidOperationException("Out of handles!");
} }
_completionEvent.WritableEvent.Signal();
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(completionEventHandle); context.Response.HandleDesc = IpcHandleDesc.MakeCopy(completionEventHandle);
return ResultCode.Success; return ResultCode.Success;
@@ -187,6 +189,20 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
return ResultCode.Success; return ResultCode.Success;
} }
[CommandCmif(10420)]
// nn::friends::CheckBlockedUserListAvailability(nn::account::Uid userId) -> bool
public ResultCode CheckBlockedUserListAvailability(ServiceCtx context)
{
UserId userId = context.RequestData.ReadStruct<UserId>();
// Yes, it is available.
context.ResponseData.Write(true);
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() });
return ResultCode.Success;
}
[CommandCmif(10600)] [CommandCmif(10600)]
// nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid userId) // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid userId)
public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context) public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context)

View File

@@ -669,6 +669,12 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
lock (Core.Lock) lock (Core.Lock)
{ {
// If we are replacing a buffer that has already been queued, make sure we release the references.
if (Core.Slots[slot].BufferState == BufferState.Queued)
{
Core.Slots[slot].GraphicBuffer.Object.DecrementNvMapHandleRefCount(Core.Owner);
}
Core.Slots[slot].BufferState = BufferState.Free; Core.Slots[slot].BufferState = BufferState.Free;
Core.Slots[slot].Fence = AndroidFence.NoFence; Core.Slots[slot].Fence = AndroidFence.NoFence;
Core.Slots[slot].RequestBufferCalled = false; Core.Slots[slot].RequestBufferCalled = false;