Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
0e8e735a6d | |||
0003a7c118 | |||
2cdcfe46d8 | |||
fe30c03cac | |||
5813b2e354 | |||
af1906ea04 | |||
68848000f7 | |||
d98da47a0f |
@ -44,7 +44,7 @@
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.1" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
|
@ -740,6 +740,18 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
||||
|
||||
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
||||
if (_running)
|
||||
{
|
||||
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
||||
var oldFiles = Directory.EnumerateFiles(HomeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||
var newFiles = Directory.EnumerateFiles(UpdatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(HomeDir, filename));
|
||||
|
||||
// Remove user files from the paths in files.
|
||||
files = files.Except(userFiles);
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
foreach (string dir in WindowsDependencyDirs)
|
||||
|
@ -32,10 +32,10 @@
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<flex:FlexPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Stretch"
|
||||
AlignContent="FlexStart"
|
||||
JustifyContent="Center" />
|
||||
JustifyContent="FlexStart" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.Styles>
|
||||
|
@ -34,6 +34,8 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool SupportsCubemapView;
|
||||
public readonly bool SupportsNonConstantTextureOffset;
|
||||
public readonly bool SupportsShaderBallot;
|
||||
public readonly bool SupportsShaderBarrierDivergence;
|
||||
public readonly bool SupportsShaderFloat64;
|
||||
public readonly bool SupportsTextureShadowLod;
|
||||
public readonly bool SupportsViewportIndexVertexTessellation;
|
||||
public readonly bool SupportsViewportMask;
|
||||
@ -81,6 +83,8 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supportsCubemapView,
|
||||
bool supportsNonConstantTextureOffset,
|
||||
bool supportsShaderBallot,
|
||||
bool supportsShaderBarrierDivergence,
|
||||
bool supportsShaderFloat64,
|
||||
bool supportsTextureShadowLod,
|
||||
bool supportsViewportIndexVertexTessellation,
|
||||
bool supportsViewportMask,
|
||||
@ -124,6 +128,8 @@ namespace Ryujinx.Graphics.GAL
|
||||
SupportsCubemapView = supportsCubemapView;
|
||||
SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
|
||||
SupportsShaderBallot = supportsShaderBallot;
|
||||
SupportsShaderBarrierDivergence = supportsShaderBarrierDivergence;
|
||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||
SupportsTextureShadowLod = supportsTextureShadowLod;
|
||||
SupportsViewportIndexVertexTessellation = supportsViewportIndexVertexTessellation;
|
||||
SupportsViewportMask = supportsViewportMask;
|
||||
|
@ -151,8 +151,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
|
||||
ShaderProgramInfo info = cs.Shaders[0].Info;
|
||||
|
||||
bool hasUnaligned = _channel.BufferManager.HasUnalignedStorageBuffers;
|
||||
|
||||
for (int index = 0; index < info.SBuffers.Count; index++)
|
||||
{
|
||||
BufferDescriptor sb = info.SBuffers[index];
|
||||
@ -177,9 +175,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
_channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), size, sb.Flags);
|
||||
}
|
||||
|
||||
if ((_channel.BufferManager.HasUnalignedStorageBuffers) != hasUnaligned)
|
||||
if (_channel.BufferManager.HasUnalignedStorageBuffers != computeState.HasUnalignedStorageBuffer)
|
||||
{
|
||||
// Refetch the shader, as assumptions about storage buffer alignment have changed.
|
||||
computeState = new GpuChannelComputeState(
|
||||
qmd.CtaThreadDimension0,
|
||||
qmd.CtaThreadDimension1,
|
||||
qmd.CtaThreadDimension2,
|
||||
localMemorySize,
|
||||
sharedMemorySize,
|
||||
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||
|
||||
cs = memoryManager.Physical.ShaderCache.GetComputeShader(_channel, poolState, computeState, shaderGpuVa);
|
||||
|
||||
_context.Renderer.Pipeline.SetProgram(cs.HostProgram);
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 4992;
|
||||
private const uint CodeGenVersion = 5044;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@ -141,6 +141,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
|
||||
|
||||
public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence;
|
||||
|
||||
public bool QueryHostSupportsShaderFloat64() => _context.Capabilities.SupportsShaderFloat64;
|
||||
|
||||
public bool QueryHostSupportsSnormBufferTextureFormat() => _context.Capabilities.SupportsSnormBufferTextureFormat;
|
||||
|
||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||
|
@ -127,6 +127,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
public Capabilities GetCapabilities()
|
||||
{
|
||||
bool intelWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelWindows;
|
||||
bool intelUnix = HwCapabilities.Vendor == HwCapabilities.GpuVendor.IntelUnix;
|
||||
bool amdWindows = HwCapabilities.Vendor == HwCapabilities.GpuVendor.AmdWindows;
|
||||
|
||||
return new Capabilities(
|
||||
@ -158,6 +159,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supportsCubemapView: true,
|
||||
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
|
||||
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
|
||||
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
|
||||
supportsShaderFloat64: true,
|
||||
supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
|
||||
supportsViewportIndexVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
||||
supportsViewportMask: HwCapabilities.SupportsViewportArray2,
|
||||
|
@ -28,18 +28,18 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
for (int i = 1; i < info.Functions.Count; i++)
|
||||
{
|
||||
PrintFunction(context, info, info.Functions[i]);
|
||||
PrintFunction(context, info.Functions[i]);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
PrintFunction(context, info, info.Functions[0], MainFunctionName);
|
||||
PrintFunction(context, info.Functions[0], MainFunctionName);
|
||||
|
||||
return context.GetCode();
|
||||
}
|
||||
|
||||
private static void PrintFunction(CodeGenContext context, StructuredProgramInfo info, StructuredFunction function, string funcName = null)
|
||||
private static void PrintFunction(CodeGenContext context, StructuredFunction function, string funcName = null)
|
||||
{
|
||||
context.CurrentFunction = function;
|
||||
|
||||
@ -48,7 +48,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
Declarations.DeclareLocals(context, function);
|
||||
|
||||
PrintBlock(context, function.MainBlock);
|
||||
PrintBlock(context, function.MainBlock, funcName == MainFunctionName);
|
||||
|
||||
context.LeaveScope();
|
||||
}
|
||||
@ -72,7 +72,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
return $"{Declarations.GetVarTypeName(context, function.ReturnType)} {funcName ?? function.Name}({string.Join(", ", args)})";
|
||||
}
|
||||
|
||||
private static void PrintBlock(CodeGenContext context, AstBlock block)
|
||||
private static void PrintBlock(CodeGenContext context, AstBlock block, bool isMainFunction)
|
||||
{
|
||||
AstBlockVisitor visitor = new AstBlockVisitor(block);
|
||||
|
||||
@ -112,10 +112,32 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
};
|
||||
|
||||
bool supportsBarrierDivergence = context.Config.GpuAccessor.QueryHostSupportsShaderBarrierDivergence();
|
||||
bool mayHaveReturned = false;
|
||||
|
||||
foreach (IAstNode node in visitor.Visit())
|
||||
{
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
if (!supportsBarrierDivergence)
|
||||
{
|
||||
if (operation.Inst == IntermediateRepresentation.Instruction.Barrier)
|
||||
{
|
||||
// Barrier on divergent control flow paths may cause the GPU to hang,
|
||||
// so skip emitting the barrier for those cases.
|
||||
if (visitor.Block.Type != AstBlockType.Main || mayHaveReturned || !isMainFunction)
|
||||
{
|
||||
context.Config.GpuAccessor.Log($"Shader has barrier on potentially divergent block, the barrier will be removed.");
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (operation.Inst == IntermediateRepresentation.Instruction.Return)
|
||||
{
|
||||
mayHaveReturned = true;
|
||||
}
|
||||
}
|
||||
|
||||
string expr = InstGen.GetExpression(context, operation);
|
||||
|
||||
if (expr != null)
|
||||
|
@ -76,6 +76,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
public SpirvDelegates Delegates { get; }
|
||||
|
||||
public bool IsMainFunction { get; private set; }
|
||||
public bool MayHaveReturned { get; set; }
|
||||
|
||||
public CodeGenContext(
|
||||
StructuredProgramInfo info,
|
||||
ShaderConfig config,
|
||||
@ -108,8 +111,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
Delegates = new SpirvDelegates(this);
|
||||
}
|
||||
|
||||
public void StartFunction()
|
||||
public void StartFunction(bool isMainFunction)
|
||||
{
|
||||
IsMainFunction = isMainFunction;
|
||||
MayHaveReturned = false;
|
||||
_locals.Clear();
|
||||
_localForArgs.Clear();
|
||||
_funcArgs.Clear();
|
||||
|
@ -242,6 +242,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
private static OperationResult GenerateBarrier(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
// Barrier on divergent control flow paths may cause the GPU to hang,
|
||||
// so skip emitting the barrier for those cases.
|
||||
if (!context.Config.GpuAccessor.QueryHostSupportsShaderBarrierDivergence() &&
|
||||
(context.CurrentBlock.Type != AstBlockType.Main || context.MayHaveReturned || !context.IsMainFunction))
|
||||
{
|
||||
context.Config.GpuAccessor.Log($"Shader has barrier on potentially divergent block, the barrier will be removed.");
|
||||
|
||||
return OperationResult.Invalid;
|
||||
}
|
||||
|
||||
context.ControlBarrier(
|
||||
context.Constant(context.TypeU32(), Scope.Workgroup),
|
||||
context.Constant(context.TypeU32(), Scope.Workgroup),
|
||||
@ -1092,6 +1102,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
private static OperationResult GenerateReturn(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
context.MayHaveReturned = true;
|
||||
|
||||
if (operation.SourcesCount != 0)
|
||||
{
|
||||
context.ReturnValue(context.Get(context.CurrentFunction.ReturnType, operation.GetSource(0)));
|
||||
|
@ -148,7 +148,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
context.CurrentFunction = function;
|
||||
context.AddFunction(spvFunc);
|
||||
context.StartFunction();
|
||||
context.StartFunction(isMainFunction: funcIndex == 0);
|
||||
|
||||
Declarations.DeclareParameters(context, function);
|
||||
|
||||
|
@ -331,6 +331,24 @@ namespace Ryujinx.Graphics.Shader
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU shader support for barrier instructions on divergent control flow paths.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU supports barriers on divergent control flow paths, false otherwise</returns>
|
||||
bool QueryHostSupportsShaderBarrierDivergence()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU support for 64-bit floating point (double precision) operations on the shader.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU and driver supports double operations, false otherwise</returns>
|
||||
bool QueryHostSupportsShaderFloat64()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU support for signed normalized buffer texture formats.
|
||||
/// </summary>
|
||||
|
@ -255,5 +255,35 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
|
||||
_sources = new Operand[] { source };
|
||||
}
|
||||
|
||||
public void TurnDoubleIntoFloat()
|
||||
{
|
||||
if ((Inst & ~Instruction.Mask) == Instruction.FP64)
|
||||
{
|
||||
Inst = (Inst & Instruction.Mask) | Instruction.FP32;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Inst)
|
||||
{
|
||||
case Instruction.ConvertFP32ToFP64:
|
||||
case Instruction.ConvertFP64ToFP32:
|
||||
Inst = Instruction.Copy;
|
||||
break;
|
||||
case Instruction.ConvertFP64ToS32:
|
||||
Inst = Instruction.ConvertFP32ToS32;
|
||||
break;
|
||||
case Instruction.ConvertFP64ToU32:
|
||||
Inst = Instruction.ConvertFP32ToU32;
|
||||
break;
|
||||
case Instruction.ConvertS32ToFP64:
|
||||
Inst = Instruction.ConvertS32ToFP32;
|
||||
break;
|
||||
case Instruction.ConvertU32ToFP64:
|
||||
Inst = Instruction.ConvertU32ToFP32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -45,12 +45,101 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
return functionName switch
|
||||
{
|
||||
HelperFunctionName.ConvertDoubleToFloat => GenerateConvertDoubleToFloatFunction(),
|
||||
HelperFunctionName.ConvertFloatToDouble => GenerateConvertFloatToDoubleFunction(),
|
||||
HelperFunctionName.TexelFetchScale => GenerateTexelFetchScaleFunction(),
|
||||
HelperFunctionName.TextureSizeUnscale => GenerateTextureSizeUnscaleFunction(),
|
||||
_ => throw new ArgumentException($"Invalid function name {functionName}")
|
||||
};
|
||||
}
|
||||
|
||||
private Function GenerateConvertDoubleToFloatFunction()
|
||||
{
|
||||
EmitterContext context = new EmitterContext();
|
||||
|
||||
Operand valueLow = Argument(0);
|
||||
Operand valueHigh = Argument(1);
|
||||
|
||||
Operand mantissaLow = context.BitwiseAnd(valueLow, Const(((1 << 22) - 1)));
|
||||
Operand mantissa = context.ShiftRightU32(valueLow, Const(22));
|
||||
|
||||
mantissa = context.BitwiseOr(mantissa, context.ShiftLeft(context.BitwiseAnd(valueHigh, Const(0xfffff)), Const(10)));
|
||||
mantissa = context.BitwiseOr(mantissa, context.ConditionalSelect(mantissaLow, Const(1), Const(0)));
|
||||
|
||||
Operand exp = context.BitwiseAnd(context.ShiftRightU32(valueHigh, Const(20)), Const(0x7ff));
|
||||
Operand sign = context.ShiftRightS32(valueHigh, Const(31));
|
||||
|
||||
Operand resultSign = context.ShiftLeft(sign, Const(31));
|
||||
|
||||
Operand notZero = context.BitwiseOr(mantissa, exp);
|
||||
|
||||
Operand lblNotZero = Label();
|
||||
|
||||
context.BranchIfTrue(lblNotZero, notZero);
|
||||
|
||||
context.Return(resultSign);
|
||||
|
||||
context.MarkLabel(lblNotZero);
|
||||
|
||||
Operand notNaNOrInf = context.ICompareNotEqual(exp, Const(0x7ff));
|
||||
|
||||
mantissa = context.BitwiseOr(mantissa, Const(0x40000000));
|
||||
exp = context.ISubtract(exp, Const(0x381));
|
||||
|
||||
// Note: Overflow cases are not handled here and might produce incorrect results.
|
||||
|
||||
Operand roundBits = context.BitwiseAnd(mantissa, Const(0x7f));
|
||||
Operand roundBitsXor64 = context.BitwiseExclusiveOr(roundBits, Const(0x40));
|
||||
mantissa = context.ShiftRightU32(context.IAdd(mantissa, Const(0x40)), Const(7));
|
||||
mantissa = context.BitwiseAnd(mantissa, context.ConditionalSelect(roundBitsXor64, Const(~0), Const(~1)));
|
||||
|
||||
exp = context.ConditionalSelect(mantissa, exp, Const(0));
|
||||
exp = context.ConditionalSelect(notNaNOrInf, exp, Const(0xff));
|
||||
|
||||
Operand result = context.IAdd(context.IAdd(mantissa, context.ShiftLeft(exp, Const(23))), resultSign);
|
||||
|
||||
context.Return(result);
|
||||
|
||||
return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, "ConvertDoubleToFloat", true, 2, 0);
|
||||
}
|
||||
|
||||
private Function GenerateConvertFloatToDoubleFunction()
|
||||
{
|
||||
EmitterContext context = new EmitterContext();
|
||||
|
||||
Operand value = Argument(0);
|
||||
|
||||
Operand mantissa = context.BitwiseAnd(value, Const(0x7fffff));
|
||||
Operand exp = context.BitwiseAnd(context.ShiftRightU32(value, Const(23)), Const(0xff));
|
||||
Operand sign = context.ShiftRightS32(value, Const(31));
|
||||
|
||||
Operand notNaNOrInf = context.ICompareNotEqual(exp, Const(0xff));
|
||||
Operand expNotZero = context.ICompareNotEqual(exp, Const(0));
|
||||
Operand notDenorm = context.BitwiseOr(expNotZero, context.ICompareEqual(mantissa, Const(0)));
|
||||
|
||||
exp = context.IAdd(exp, Const(0x380));
|
||||
|
||||
Operand shiftDist = context.ISubtract(Const(32), context.FindMSBU32(mantissa));
|
||||
Operand normExp = context.ISubtract(context.ISubtract(Const(1), shiftDist), Const(1));
|
||||
Operand normMant = context.ShiftLeft(mantissa, shiftDist);
|
||||
|
||||
exp = context.ConditionalSelect(notNaNOrInf, exp, Const(0x7ff));
|
||||
exp = context.ConditionalSelect(notDenorm, exp, normExp);
|
||||
mantissa = context.ConditionalSelect(expNotZero, mantissa, normMant);
|
||||
|
||||
Operand resultLow = context.ShiftLeft(mantissa, Const(29));
|
||||
Operand resultHigh = context.ShiftRightU32(mantissa, Const(3));
|
||||
|
||||
resultHigh = context.IAdd(resultHigh, context.ShiftLeft(exp, Const(20)));
|
||||
resultHigh = context.IAdd(resultHigh, context.ShiftLeft(sign, Const(31)));
|
||||
|
||||
context.Copy(Argument(1), resultLow);
|
||||
context.Copy(Argument(2), resultHigh);
|
||||
context.Return();
|
||||
|
||||
return new Function(ControlFlowGraph.Create(context.GetOperations()).Blocks, "ConvertFloatToDouble", false, 1, 2);
|
||||
}
|
||||
|
||||
private Function GenerateTexelFetchScaleFunction()
|
||||
{
|
||||
EmitterContext context = new EmitterContext();
|
||||
|
@ -1,10 +1,9 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
enum HelperFunctionName
|
||||
{
|
||||
ConvertDoubleToFloat,
|
||||
ConvertFloatToDouble,
|
||||
TexelFetchScale,
|
||||
TextureSizeUnscale
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
static class DoubleToFloat
|
||||
{
|
||||
public static void RunPass(HelperFunctionManager hfm, BasicBlock block)
|
||||
{
|
||||
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||
{
|
||||
if (node.Value is not Operation operation)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node = InsertSoftFloat64(hfm, node);
|
||||
}
|
||||
}
|
||||
|
||||
private static LinkedListNode<INode> InsertSoftFloat64(HelperFunctionManager hfm, LinkedListNode<INode> node)
|
||||
{
|
||||
Operation operation = (Operation)node.Value;
|
||||
|
||||
if (operation.Inst == Instruction.PackDouble2x32)
|
||||
{
|
||||
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.ConvertDoubleToFloat);
|
||||
|
||||
Operand[] callArgs = new Operand[] { Const(functionId), operation.GetSource(0), operation.GetSource(1) };
|
||||
|
||||
Operand floatValue = operation.Dest;
|
||||
|
||||
operation.Dest = null;
|
||||
|
||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, floatValue, callArgs));
|
||||
|
||||
Utils.DeleteNode(node, operation);
|
||||
|
||||
return newNode;
|
||||
}
|
||||
else if (operation.Inst == Instruction.UnpackDouble2x32)
|
||||
{
|
||||
int functionId = hfm.GetOrCreateFunctionId(HelperFunctionName.ConvertFloatToDouble);
|
||||
|
||||
// TODO: Allow UnpackDouble2x32 to produce two outputs and get rid of "operation.Index".
|
||||
|
||||
Operand resultLow = operation.Index == 0 ? operation.Dest : Local();
|
||||
Operand resultHigh = operation.Index == 1 ? operation.Dest : Local();
|
||||
|
||||
operation.Dest = null;
|
||||
|
||||
Operand[] callArgs = new Operand[] { Const(functionId), operation.GetSource(0), resultLow, resultHigh };
|
||||
|
||||
LinkedListNode<INode> newNode = node.List.AddBefore(node, new Operation(Instruction.Call, 0, (Operand)null, callArgs));
|
||||
|
||||
Utils.DeleteNode(node, operation);
|
||||
|
||||
return newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
operation.TurnDoubleIntoFloat();
|
||||
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,8 +11,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
RunOptimizationPasses(blocks, config);
|
||||
|
||||
// TODO: Some of those are not optimizations and shouldn't be here.
|
||||
|
||||
GlobalToStorage.RunPass(hfm, blocks, config);
|
||||
|
||||
bool hostSupportsShaderFloat64 = config.GpuAccessor.QueryHostSupportsShaderFloat64();
|
||||
|
||||
// Those passes are looking for specific patterns and only needs to run once.
|
||||
for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
|
||||
{
|
||||
@ -24,6 +28,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
{
|
||||
EliminateMultiplyByFragmentCoordW(blocks[blkIndex]);
|
||||
}
|
||||
|
||||
// If the host does not support double operations, we need to turn them into float operations.
|
||||
if (!hostSupportsShaderFloat64)
|
||||
{
|
||||
DoubleToFloat.RunPass(hfm, blocks[blkIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
// Run optimizations one last time to remove any code that is now optimizable after above passes.
|
||||
|
@ -90,6 +90,7 @@ namespace Ryujinx.Graphics.Texture
|
||||
|
||||
mipOffsets[level] = layerSize;
|
||||
sliceSizes[level] = totalBlocksOfGobsInY * robSize;
|
||||
levelSizes[level] = totalBlocksOfGobsInZ * sliceSizes[level];
|
||||
|
||||
if (is3D)
|
||||
{
|
||||
@ -116,12 +117,15 @@ namespace Ryujinx.Graphics.Texture
|
||||
// The slice only covers up to the end of this slice's depth, rather than the full aligned size.
|
||||
// Avoids size being too large on partial views of 3d textures.
|
||||
|
||||
sliceSizes[level] -= gobSize * (mipGobBlocksInZ - gobRemainderZ);
|
||||
levelSizes[level] -= gobSize * (mipGobBlocksInZ - gobRemainderZ);
|
||||
|
||||
if (sliceSizes[level] > levelSizes[level])
|
||||
{
|
||||
sliceSizes[level] = levelSizes[level];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
levelSizes[level] = totalBlocksOfGobsInZ * sliceSizes[level];
|
||||
|
||||
layerSize += levelSizes[level];
|
||||
|
||||
depthLevelOffset += d;
|
||||
|
@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly bool SupportsFragmentShaderInterlock;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
public readonly bool SupportsSubgroupSizeControl;
|
||||
public readonly bool SupportsShaderFloat64;
|
||||
public readonly bool SupportsShaderInt8;
|
||||
public readonly bool SupportsShaderStencilExport;
|
||||
public readonly bool SupportsShaderStorageImageMultisample;
|
||||
@ -63,6 +64,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
bool supportsFragmentShaderInterlock,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
bool supportsSubgroupSizeControl,
|
||||
bool supportsShaderFloat64,
|
||||
bool supportsShaderInt8,
|
||||
bool supportsShaderStencilExport,
|
||||
bool supportsShaderStorageImageMultisample,
|
||||
@ -99,6 +101,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
SupportsSubgroupSizeControl = supportsSubgroupSizeControl;
|
||||
SupportsShaderFloat64 = supportsShaderFloat64;
|
||||
SupportsShaderInt8 = supportsShaderInt8;
|
||||
SupportsShaderStencilExport = supportsShaderStencilExport;
|
||||
SupportsShaderStorageImageMultisample = supportsShaderStorageImageMultisample;
|
||||
|
@ -15,6 +15,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Device _device;
|
||||
|
||||
private readonly Auto<DisposableImageView> _imageView;
|
||||
private readonly Auto<DisposableImageView> _imageViewDraw;
|
||||
private readonly Auto<DisposableImageView> _imageViewIdentity;
|
||||
private readonly Auto<DisposableImageView> _imageView2dArray;
|
||||
private Dictionary<GAL.Format, TextureView> _selfManagedViews;
|
||||
@ -127,7 +128,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ComponentSwizzle.B,
|
||||
ComponentSwizzle.A);
|
||||
|
||||
_imageViewIdentity = CreateImageView(identityComponentMapping, subresourceRangeDepth, type, usage);
|
||||
_imageViewDraw = CreateImageView(identityComponentMapping, subresourceRangeDepth, type, usage);
|
||||
_imageViewIdentity = aspectFlagsDepth == aspectFlags ? _imageViewDraw : CreateImageView(identityComponentMapping, subresourceRange, type, usage);
|
||||
|
||||
// Framebuffer attachments also require 3D textures to be bound as 2D array.
|
||||
if (info.Target == Target.Texture3D)
|
||||
@ -169,7 +171,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public Auto<DisposableImageView> GetImageViewForAttachment()
|
||||
{
|
||||
return _imageView2dArray ?? _imageViewIdentity;
|
||||
return _imageView2dArray ?? _imageViewDraw;
|
||||
}
|
||||
|
||||
public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
|
||||
@ -909,6 +911,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_imageViewIdentity.Dispose();
|
||||
_imageView2dArray?.Dispose();
|
||||
|
||||
if (_imageViewDraw != _imageViewIdentity)
|
||||
{
|
||||
_imageViewDraw.Dispose();
|
||||
}
|
||||
|
||||
Storage.DecrementViewsCount();
|
||||
}
|
||||
}
|
||||
|
@ -306,6 +306,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_fragment_shader_interlock"),
|
||||
_physicalDevice.IsDeviceExtensionPresent("VK_NV_geometry_shader_passthrough"),
|
||||
supportsSubgroupSizeControl,
|
||||
features2.Features.ShaderFloat64,
|
||||
featuresShaderInt8.ShaderInt8,
|
||||
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_shader_stencil_export"),
|
||||
features2.Features.ShaderStorageImageMultisample,
|
||||
@ -594,6 +595,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
supportsCubemapView: !IsAmdGcn,
|
||||
supportsNonConstantTextureOffset: false,
|
||||
supportsShaderBallot: false,
|
||||
supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
|
||||
supportsShaderFloat64: Capabilities.SupportsShaderFloat64,
|
||||
supportsTextureShadowLod: false,
|
||||
supportsViewportIndexVertexTessellation: featuresVk12.ShaderOutputViewportIndex,
|
||||
supportsViewportMask: Capabilities.SupportsViewportArray2,
|
||||
|
@ -565,6 +565,18 @@ namespace Ryujinx.Modules
|
||||
{
|
||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
||||
|
||||
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
||||
if (Running)
|
||||
{
|
||||
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
||||
var oldFiles = Directory.EnumerateFiles(HomeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||
var newFiles = Directory.EnumerateFiles(UpdatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(HomeDir, filename));
|
||||
|
||||
// Remove user files from the paths in files.
|
||||
files = files.Except(userFiles);
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
foreach (string dir in WindowsDependencyDirs)
|
||||
|
Reference in New Issue
Block a user