Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bbb24d8c7e | ||
|
4da44e09cb | ||
|
ae13f0ab4d | ||
|
a2a35f1be6 | ||
|
aedfadaaf7 | ||
|
5c0fb0cec3 | ||
|
17a1cab5d2 | ||
|
73aed239c3 | ||
|
9ac66336a2 | ||
|
4965681e06 | ||
|
3868a00206 | ||
|
933e5144a9 | ||
|
73a42c85c4 | ||
|
39ba11054b |
@@ -89,6 +89,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
struct AllocationResult
|
||||
readonly struct AllocationResult
|
||||
{
|
||||
public int IntUsedRegisters { get; }
|
||||
public int VecUsedRegisters { get; }
|
||||
|
@@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
private class ParallelCopy
|
||||
{
|
||||
private struct Copy
|
||||
private readonly struct Copy
|
||||
{
|
||||
public Register Dest { get; }
|
||||
public Register Source { get; }
|
||||
|
@@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
class HybridAllocator : IRegisterAllocator
|
||||
{
|
||||
private struct BlockInfo
|
||||
private readonly struct BlockInfo
|
||||
{
|
||||
public bool HasCall { get; }
|
||||
|
||||
|
@@ -3,7 +3,7 @@ using System;
|
||||
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
struct RegisterMasks
|
||||
readonly struct RegisterMasks
|
||||
{
|
||||
public int IntAvailableRegisters { get; }
|
||||
public int VecAvailableRegisters { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
struct IntrinsicInfo
|
||||
readonly struct IntrinsicInfo
|
||||
{
|
||||
public X86Instruction Inst { get; }
|
||||
public IntrinsicType Type { get; }
|
||||
|
@@ -2,7 +2,7 @@ using ARMeilleure.Instructions;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
struct InstDescriptor
|
||||
readonly struct InstDescriptor
|
||||
{
|
||||
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
|
||||
|
||||
|
@@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
private const int FastLookupSize = 0x1000;
|
||||
|
||||
private struct InstInfo
|
||||
private readonly struct InstInfo
|
||||
{
|
||||
public int Mask { get; }
|
||||
public int Value { get; }
|
||||
|
@@ -6,7 +6,7 @@ namespace ARMeilleure.Diagnostics
|
||||
{
|
||||
static class Symbols
|
||||
{
|
||||
private struct RangedSymbol
|
||||
private readonly struct RangedSymbol
|
||||
{
|
||||
public readonly ulong Start;
|
||||
public readonly ulong End;
|
||||
|
@@ -3,7 +3,7 @@ using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
struct PhiOperation
|
||||
readonly struct PhiOperation
|
||||
{
|
||||
private readonly Operation _operation;
|
||||
|
||||
|
@@ -2,7 +2,7 @@ using System;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
struct Register : IEquatable<Register>
|
||||
readonly struct Register : IEquatable<Register>
|
||||
{
|
||||
public int Index { get; }
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
struct CacheEntry : IComparable<CacheEntry>
|
||||
readonly struct CacheEntry : IComparable<CacheEntry>
|
||||
{
|
||||
public int Offset { get; }
|
||||
public int Size { get; }
|
||||
|
@@ -6,7 +6,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
class CacheMemoryAllocator
|
||||
{
|
||||
private struct MemoryBlock : IComparable<MemoryBlock>
|
||||
private readonly struct MemoryBlock : IComparable<MemoryBlock>
|
||||
{
|
||||
public int Offset { get; }
|
||||
public int Size { get; }
|
||||
|
@@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
struct CompilerContext
|
||||
readonly struct CompilerContext
|
||||
{
|
||||
public ControlFlowGraph Cfg { get; }
|
||||
|
||||
|
@@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
|
||||
private const int RegsCount = 32;
|
||||
private const int RegsMask = RegsCount - 1;
|
||||
|
||||
private struct RegisterMask : IEquatable<RegisterMask>
|
||||
private readonly struct RegisterMask : IEquatable<RegisterMask>
|
||||
{
|
||||
public long IntMask => Mask.GetElement(0);
|
||||
public long VecMask => Mask.GetElement(1);
|
||||
|
@@ -293,7 +293,7 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
private struct Range
|
||||
private readonly struct Range
|
||||
{
|
||||
public ulong Start { get; }
|
||||
public ulong End { get; }
|
||||
|
@@ -21,6 +21,10 @@
|
||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://crwd.in/ryujinx">
|
||||
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://discord.com/invite/VkQYXAZ">
|
||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||
alt="Discord">
|
||||
@@ -48,6 +52,8 @@ See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ry
|
||||
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
||||
|
||||
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
||||
|
||||
## Latest build
|
||||
|
||||
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
||||
|
@@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOChannelLayout
|
||||
public readonly struct SoundIOChannelLayout
|
||||
{
|
||||
public static int BuiltInCount
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOSampleRateRange
|
||||
public readonly struct SoundIOSampleRateRange
|
||||
{
|
||||
internal SoundIOSampleRateRange(int min, int max)
|
||||
{
|
||||
|
@@ -20,7 +20,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
private const int CutOffLuminosity = 64;
|
||||
|
||||
private struct PaletteColor
|
||||
private readonly struct PaletteColor
|
||||
{
|
||||
public int Qck { get; }
|
||||
public byte R { get; }
|
||||
|
@@ -266,6 +266,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
return;
|
||||
}
|
||||
|
||||
CanUpdate = false;
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
|
||||
@@ -371,6 +372,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
ViewModel.ShowContent = true;
|
||||
ViewModel.ShowLoadProgress = false;
|
||||
ViewModel.IsLoadingIndeterminate = false;
|
||||
CanUpdate = true;
|
||||
Cursor = Cursor.Default;
|
||||
|
||||
if (MainContent.Content != _mainViewContent)
|
||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.Common.Logging
|
||||
|
||||
public static event EventHandler<LogEventArgs> Updated;
|
||||
|
||||
public struct Log
|
||||
public readonly struct Log
|
||||
{
|
||||
internal readonly LogLevel Level;
|
||||
|
||||
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Common.Memory
|
||||
/// This is useful to keep the Array representation when possible to avoid copies.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Element Type</typeparam>
|
||||
public ref struct SpanOrArray<T> where T : unmanaged
|
||||
public readonly ref struct SpanOrArray<T> where T : unmanaged
|
||||
{
|
||||
public readonly T[] Array;
|
||||
public readonly ReadOnlySpan<T> Span;
|
||||
|
@@ -28,9 +28,39 @@ namespace Ryujinx.Common.SystemInfo
|
||||
|
||||
CpuName = $"{cpuName} ; {LogicalCoreCount} logical";
|
||||
RamTotal = totalRAM;
|
||||
RamAvailable = GetVMInfoAvailableMemory();
|
||||
}
|
||||
|
||||
[DllImport("libSystem.dylib", CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
static ulong GetVMInfoAvailableMemory()
|
||||
{
|
||||
var port = mach_host_self();
|
||||
|
||||
uint pageSize = 0;
|
||||
var result = host_page_size(port, ref pageSize);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_page_size() error = {result}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int flavor = 4; // HOST_VM_INFO64
|
||||
uint count = (uint)(Marshal.SizeOf<VMStatistics64>() / sizeof(int)); // HOST_VM_INFO64_COUNT
|
||||
VMStatistics64 stats = new();
|
||||
result = host_statistics64(port, flavor, ref stats, ref count);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to query Available RAM. host_statistics64() error = {result}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (ulong)(stats.FreeCount + stats.InactiveCount) * pageSize;
|
||||
}
|
||||
|
||||
private const string SystemLibraryName = "libSystem.dylib";
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
|
||||
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
|
||||
@@ -85,5 +115,43 @@ namespace Ryujinx.Common.SystemInfo
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern uint mach_host_self();
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern int host_page_size(uint host, ref uint out_page_size);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
struct VMStatistics64
|
||||
{
|
||||
public uint FreeCount;
|
||||
public uint ActiveCount;
|
||||
public uint InactiveCount;
|
||||
public uint WireCount;
|
||||
public ulong ZeroFillCount;
|
||||
public ulong Reactivations;
|
||||
public ulong Pageins;
|
||||
public ulong Pageouts;
|
||||
public ulong Faults;
|
||||
public ulong CowFaults;
|
||||
public ulong Lookups;
|
||||
public ulong Hits;
|
||||
public ulong Purges;
|
||||
public uint PurgeableCount;
|
||||
public uint SpeculativeCount;
|
||||
public ulong Decompressions;
|
||||
public ulong Compressions;
|
||||
public ulong Swapins;
|
||||
public ulong Swapouts;
|
||||
public uint CompressorPageCount;
|
||||
public uint ThrottledCount;
|
||||
public uint ExternalPageCount;
|
||||
public uint InternalPageCount;
|
||||
public ulong TotalUncompressedPagesInCompressor;
|
||||
}
|
||||
|
||||
[DllImport(SystemLibraryName, CharSet = CharSet.Ansi, SetLastError = true)]
|
||||
private static extern int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
|
||||
}
|
||||
}
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Cpu
|
||||
/// <summary>
|
||||
/// Stores handlers for the various CPU exceptions.
|
||||
/// </summary>
|
||||
public struct ExceptionCallbacks
|
||||
public readonly struct ExceptionCallbacks
|
||||
{
|
||||
/// <summary>
|
||||
/// Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/>.
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Ryujinx.Graphics.Device
|
||||
{
|
||||
public struct RwCallback
|
||||
public readonly struct RwCallback
|
||||
{
|
||||
public Action<int> Write { get; }
|
||||
public Func<int> Read { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct BlendDescriptor
|
||||
public readonly struct BlendDescriptor
|
||||
{
|
||||
public bool Enable { get; }
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct BufferAssignment
|
||||
public readonly struct BufferAssignment
|
||||
{
|
||||
public readonly int Binding;
|
||||
public readonly BufferRange Range;
|
||||
|
@@ -1,22 +1,14 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 8)]
|
||||
public struct BufferHandle : IEquatable<BufferHandle>
|
||||
public readonly record struct BufferHandle
|
||||
{
|
||||
private readonly ulong _value;
|
||||
|
||||
public static BufferHandle Null => new BufferHandle(0);
|
||||
|
||||
private BufferHandle(ulong value) => _value = value;
|
||||
|
||||
public override bool Equals(object obj) => obj is BufferHandle handle && Equals(handle);
|
||||
public bool Equals([AllowNull] BufferHandle other) => other._value == _value;
|
||||
public override int GetHashCode() => _value.GetHashCode();
|
||||
public static bool operator ==(BufferHandle left, BufferHandle right) => left.Equals(right);
|
||||
public static bool operator !=(BufferHandle left, BufferHandle right) => !(left == right);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct BufferRange
|
||||
public readonly struct BufferRange
|
||||
{
|
||||
private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);
|
||||
|
||||
|
@@ -2,7 +2,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct Capabilities
|
||||
public readonly struct Capabilities
|
||||
{
|
||||
public readonly TargetApi Api;
|
||||
public readonly string VendorName;
|
||||
@@ -17,6 +17,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool Supports3DTextureCompression;
|
||||
public readonly bool SupportsBgraFormat;
|
||||
public readonly bool SupportsR4G4Format;
|
||||
public readonly bool SupportsSnormBufferTextureFormat;
|
||||
public readonly bool SupportsFragmentShaderInterlock;
|
||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
@@ -52,6 +53,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supports3DTextureCompression,
|
||||
bool supportsBgraFormat,
|
||||
bool supportsR4G4Format,
|
||||
bool supportsSnormBufferTextureFormat,
|
||||
bool supportsFragmentShaderInterlock,
|
||||
bool supportsFragmentShaderOrderingIntel,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
@@ -84,6 +86,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
Supports3DTextureCompression = supports3DTextureCompression;
|
||||
SupportsBgraFormat = supportsBgraFormat;
|
||||
SupportsR4G4Format = supportsR4G4Format;
|
||||
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
|
||||
SupportsFragmentShaderInterlock = supportsFragmentShaderInterlock;
|
||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
|
@@ -1,32 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct ColorF : IEquatable<ColorF>
|
||||
{
|
||||
public float Red { get; }
|
||||
public float Green { get; }
|
||||
public float Blue { get; }
|
||||
public float Alpha { get; }
|
||||
|
||||
public ColorF(float red, float green, float blue, float alpha)
|
||||
{
|
||||
Red = red;
|
||||
Green = green;
|
||||
Blue = blue;
|
||||
Alpha = alpha;
|
||||
}
|
||||
|
||||
public bool Equals(ColorF color) => Red == color.Red &&
|
||||
Green == color.Green &&
|
||||
Blue == color.Blue &&
|
||||
Alpha == color.Alpha;
|
||||
|
||||
public override bool Equals(object obj) => (obj is ColorF color) && Equals(color);
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(Red, Green, Blue, Alpha);
|
||||
|
||||
public static bool operator ==(ColorF l, ColorF r) => l.Equals(r);
|
||||
public static bool operator !=(ColorF l, ColorF r) => !l.Equals(r);
|
||||
}
|
||||
public readonly record struct ColorF(float Red, float Green, float Blue, float Alpha);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct DepthTestDescriptor
|
||||
public readonly struct DepthTestDescriptor
|
||||
{
|
||||
public bool TestEnable { get; }
|
||||
public bool WriteEnable { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct DeviceInfo
|
||||
public readonly struct DeviceInfo
|
||||
{
|
||||
public readonly string Id;
|
||||
public readonly string Vendor;
|
||||
|
@@ -2,7 +2,7 @@ using Ryujinx.Common;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct Extents2D
|
||||
public readonly struct Extents2D
|
||||
{
|
||||
public int X1 { get; }
|
||||
public int Y1 { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct Extents2DF
|
||||
public readonly struct Extents2DF
|
||||
{
|
||||
public float X1 { get; }
|
||||
public float Y1 { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct HardwareInfo
|
||||
public readonly struct HardwareInfo
|
||||
{
|
||||
public string GpuVendor { get; }
|
||||
public string GpuModel { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct ImageCrop
|
||||
public readonly struct ImageCrop
|
||||
{
|
||||
public int Left { get; }
|
||||
public int Right { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct MultisampleDescriptor
|
||||
public readonly struct MultisampleDescriptor
|
||||
{
|
||||
public bool AlphaToCoverageEnable { get; }
|
||||
public bool AlphaToCoverageDitherEnable { get; }
|
||||
|
@@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
/// <summary>
|
||||
/// Descriptor for a pipeline buffer binding.
|
||||
/// </summary>
|
||||
public struct BufferPipelineDescriptor
|
||||
public readonly struct BufferPipelineDescriptor
|
||||
{
|
||||
public bool Enable { get; }
|
||||
public int Stride { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct Rectangle<T> where T : unmanaged
|
||||
public readonly struct Rectangle<T> where T : unmanaged
|
||||
{
|
||||
public T X { get; }
|
||||
public T Y { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct SamplerCreateInfo
|
||||
public readonly struct SamplerCreateInfo
|
||||
{
|
||||
public MinFilter MinFilter { get; }
|
||||
public MagFilter MagFilter { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct ScreenCaptureImageInfo
|
||||
public readonly struct ScreenCaptureImageInfo
|
||||
{
|
||||
public ScreenCaptureImageInfo(int width, int height, bool isBgra, byte[] data, bool flipX, bool flipY)
|
||||
{
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct ShaderBindings
|
||||
public readonly struct ShaderBindings
|
||||
{
|
||||
public IReadOnlyCollection<int> UniformBufferBindings { get; }
|
||||
public IReadOnlyCollection<int> StorageBufferBindings { get; }
|
||||
|
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct ShaderSource
|
||||
public readonly struct ShaderSource
|
||||
{
|
||||
public string Code { get; }
|
||||
public byte[] BinaryCode { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct StencilTestDescriptor
|
||||
public readonly struct StencilTestDescriptor
|
||||
{
|
||||
public bool TestEnable { get; }
|
||||
|
||||
|
@@ -4,7 +4,7 @@ using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct TextureCreateInfo : IEquatable<TextureCreateInfo>
|
||||
public readonly struct TextureCreateInfo : IEquatable<TextureCreateInfo>
|
||||
{
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
@@ -62,42 +62,42 @@ namespace Ryujinx.Graphics.GAL
|
||||
SwizzleA = swizzleA;
|
||||
}
|
||||
|
||||
public readonly int GetMipSize(int level)
|
||||
public int GetMipSize(int level)
|
||||
{
|
||||
return GetMipStride(level) * GetLevelHeight(level) * GetLevelDepth(level);
|
||||
}
|
||||
|
||||
public readonly int GetMipSize2D(int level)
|
||||
public int GetMipSize2D(int level)
|
||||
{
|
||||
return GetMipStride(level) * GetLevelHeight(level);
|
||||
}
|
||||
|
||||
public readonly int GetMipStride(int level)
|
||||
public int GetMipStride(int level)
|
||||
{
|
||||
return BitUtils.AlignUp(GetLevelWidth(level) * BytesPerPixel, 4);
|
||||
}
|
||||
|
||||
private readonly int GetLevelWidth(int level)
|
||||
private int GetLevelWidth(int level)
|
||||
{
|
||||
return BitUtils.DivRoundUp(GetLevelSize(Width, level), BlockWidth);
|
||||
}
|
||||
|
||||
private readonly int GetLevelHeight(int level)
|
||||
private int GetLevelHeight(int level)
|
||||
{
|
||||
return BitUtils.DivRoundUp(GetLevelSize(Height, level), BlockHeight);
|
||||
}
|
||||
|
||||
private readonly int GetLevelDepth(int level)
|
||||
private int GetLevelDepth(int level)
|
||||
{
|
||||
return Target == Target.Texture3D ? GetLevelSize(Depth, level) : GetLayers();
|
||||
}
|
||||
|
||||
public readonly int GetDepthOrLayers()
|
||||
public int GetDepthOrLayers()
|
||||
{
|
||||
return Target == Target.Texture3D ? Depth : GetLayers();
|
||||
}
|
||||
|
||||
public readonly int GetLayers()
|
||||
public int GetLayers()
|
||||
{
|
||||
if (Target == Target.Texture2DArray ||
|
||||
Target == Target.Texture2DMultisampleArray ||
|
||||
@@ -113,7 +113,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
return 1;
|
||||
}
|
||||
|
||||
public readonly int GetLevelsClamped()
|
||||
public int GetLevelsClamped()
|
||||
{
|
||||
int maxSize = Width;
|
||||
|
||||
|
@@ -1,40 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct VertexAttribDescriptor : IEquatable<VertexAttribDescriptor>
|
||||
{
|
||||
public int BufferIndex { get; }
|
||||
public int Offset { get; }
|
||||
|
||||
public bool IsZero { get; }
|
||||
|
||||
public Format Format { get; }
|
||||
|
||||
public VertexAttribDescriptor(int bufferIndex, int offset, bool isZero, Format format)
|
||||
{
|
||||
BufferIndex = bufferIndex;
|
||||
Offset = offset;
|
||||
IsZero = isZero;
|
||||
Format = format;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is VertexAttribDescriptor other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals(VertexAttribDescriptor other)
|
||||
{
|
||||
return BufferIndex == other.BufferIndex &&
|
||||
Offset == other.Offset &&
|
||||
IsZero == other.IsZero &&
|
||||
Format == other.Format;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(BufferIndex, Offset, IsZero, Format);
|
||||
}
|
||||
}
|
||||
public readonly record struct VertexAttribDescriptor(int BufferIndex, int Offset, bool IsZero, Format Format);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct VertexBufferDescriptor
|
||||
public readonly struct VertexBufferDescriptor
|
||||
{
|
||||
public BufferRange Buffer { get; }
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct Viewport
|
||||
public readonly struct Viewport
|
||||
{
|
||||
public Rectangle<float> Region { get; }
|
||||
|
||||
|
@@ -202,57 +202,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
|
||||
}
|
||||
|
||||
_channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
|
||||
_channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
|
||||
_channel.BufferManager.SetComputeBufferBindings(cs.Bindings);
|
||||
|
||||
int maxTextureBinding = -1;
|
||||
int maxImageBinding = -1;
|
||||
|
||||
TextureBindingInfo[] textureBindings = _channel.TextureManager.RentComputeTextureBindings(info.Textures.Count);
|
||||
|
||||
for (int index = 0; index < info.Textures.Count; index++)
|
||||
{
|
||||
var descriptor = info.Textures[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
|
||||
textureBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxTextureBinding)
|
||||
{
|
||||
maxTextureBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentComputeImageBindings(info.Images.Count);
|
||||
|
||||
for (int index = 0; index < info.Images.Count; index++)
|
||||
{
|
||||
var descriptor = info.Images[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
|
||||
imageBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxImageBinding)
|
||||
{
|
||||
maxImageBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
_channel.TextureManager.SetComputeMaxBindings(maxTextureBinding, maxImageBinding);
|
||||
_channel.TextureManager.SetComputeBindings(cs.Bindings);
|
||||
|
||||
// Should never return false for mismatching spec state, since the shader was fetched above.
|
||||
_channel.TextureManager.CommitComputeBindings(cs.SpecializationState);
|
||||
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
/// <summary>
|
||||
/// FIFO word.
|
||||
/// </summary>
|
||||
struct FifoWord
|
||||
readonly struct FifoWord
|
||||
{
|
||||
/// <summary>
|
||||
/// GPU virtual address where the word is located in memory.
|
||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
/// <summary>
|
||||
/// Macroo High-level implementation table entry.
|
||||
/// </summary>
|
||||
struct TableEntry
|
||||
readonly struct TableEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the Macro function.
|
||||
|
@@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
private readonly DrawState _drawState;
|
||||
private readonly SpecializationStateUpdater _currentSpecState;
|
||||
private bool _topologySet;
|
||||
|
||||
private bool _instancedDrawPending;
|
||||
@@ -44,12 +45,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">Channel state</param>
|
||||
/// <param name="drawState">Draw state</param>
|
||||
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
|
||||
/// <param name="spec">Specialization state updater</param>
|
||||
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
_drawState = drawState;
|
||||
_currentSpecState = spec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -132,6 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.FirstIndex = firstIndex;
|
||||
_drawState.IndexCount = indexCount;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(false);
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
@@ -256,6 +260,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
if (_drawState.Topology != topology || !_topologySet)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||
_currentSpecState.SetTopology(topology);
|
||||
_drawState.Topology = topology;
|
||||
_topologySet = true;
|
||||
}
|
||||
@@ -452,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.FirstInstance = (uint)firstInstance;
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.HasConstantBufferDrawParameters = true;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(true);
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
@@ -469,7 +474,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.FirstInstance = 0;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.HasConstantBufferDrawParameters = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
@@ -527,7 +531,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.DrawIndirect = true;
|
||||
_drawState.HasConstantBufferDrawParameters = true;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(true);
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
@@ -561,7 +565,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.DrawIndirect = false;
|
||||
_drawState.HasConstantBufferDrawParameters = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
|
280
Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
Normal file
280
Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
Normal file
@@ -0,0 +1,280 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a "current" specialiation state, and provides a flag to check if it has changed meaningfully.
|
||||
/// </summary>
|
||||
internal class SpecializationStateUpdater
|
||||
{
|
||||
private GpuChannelGraphicsState _graphics;
|
||||
private GpuChannelPoolState _pool;
|
||||
|
||||
private bool _usesDrawParameters;
|
||||
private bool _usesTopology;
|
||||
|
||||
private bool _changed;
|
||||
|
||||
/// <summary>
|
||||
/// Signal that the specialization state has changed.
|
||||
/// </summary>
|
||||
private void Signal()
|
||||
{
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the specialization state has changed since the last check.
|
||||
/// </summary>
|
||||
/// <returns>True if it has changed, false otherwise</returns>
|
||||
public bool HasChanged()
|
||||
{
|
||||
if (_changed)
|
||||
{
|
||||
_changed = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the active shader, clearing the dirty state and recording if certain specializations are noteworthy.
|
||||
/// </summary>
|
||||
/// <param name="gs">The active shader</param>
|
||||
public void SetShader(CachedShaderProgram gs)
|
||||
{
|
||||
_usesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
_usesTopology = gs.SpecializationState.IsPrimitiveTopologyQueried();
|
||||
|
||||
_changed = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current graphics state.
|
||||
/// </summary>
|
||||
/// <returns>GPU graphics state</returns>
|
||||
public ref GpuChannelGraphicsState GetGraphicsState()
|
||||
{
|
||||
return ref _graphics;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current pool state.
|
||||
/// </summary>
|
||||
/// <returns>GPU pool state</returns>
|
||||
public ref GpuChannelPoolState GetPoolState()
|
||||
{
|
||||
return ref _pool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Early Z force enable.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetEarlyZForce(bool value)
|
||||
{
|
||||
_graphics.EarlyZForce = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology of current draw.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetTopology(PrimitiveTopology value)
|
||||
{
|
||||
if (value != _graphics.Topology)
|
||||
{
|
||||
_graphics.Topology = value;
|
||||
|
||||
if (_usesTopology)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tessellation mode.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetTessellationMode(TessMode value)
|
||||
{
|
||||
if (value.Packed != _graphics.TessellationMode.Packed)
|
||||
{
|
||||
_graphics.TessellationMode = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates alpha-to-coverage state, and sets it as changed.
|
||||
/// </summary>
|
||||
/// <param name="enable">Whether alpha-to-coverage is enabled</param>
|
||||
/// <param name="ditherEnable">Whether alpha-to-coverage dithering is enabled</param>
|
||||
public void SetAlphaToCoverageEnable(bool enable, bool ditherEnable)
|
||||
{
|
||||
_graphics.AlphaToCoverageEnable = enable;
|
||||
_graphics.AlphaToCoverageDitherEnable = ditherEnable;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the viewport transform is disabled.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetViewportTransformDisable(bool value)
|
||||
{
|
||||
if (value != _graphics.ViewportTransformDisable)
|
||||
{
|
||||
_graphics.ViewportTransformDisable = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Depth mode zero to one or minus one to one.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetDepthMode(bool value)
|
||||
{
|
||||
if (value != _graphics.DepthMode)
|
||||
{
|
||||
_graphics.DepthMode = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the point size is set on the shader or is fixed.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetProgramPointSizeEnable(bool value)
|
||||
{
|
||||
if (value != _graphics.ProgramPointSizeEnable)
|
||||
{
|
||||
_graphics.ProgramPointSizeEnable = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Point size used if <see cref="SetProgramPointSizeEnable" /> is provided false.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetPointSize(float value)
|
||||
{
|
||||
if (value != _graphics.PointSize)
|
||||
{
|
||||
_graphics.PointSize = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates alpha test specialization state, and sets it as changed.
|
||||
/// </summary>
|
||||
/// <param name="enable">Whether alpha test is enabled</param>
|
||||
/// <param name="reference">The value to compare with the fragment output alpha</param>
|
||||
/// <param name="op">The comparison that decides if the fragment should be discarded</param>
|
||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||
{
|
||||
_graphics.AlphaTestEnable = enable;
|
||||
_graphics.AlphaTestReference = reference;
|
||||
_graphics.AlphaTestCompare = op;
|
||||
|
||||
Signal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the type of the vertex attributes consumed by the shader.
|
||||
/// </summary>
|
||||
/// <param name="state">The new state</param>
|
||||
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
|
||||
{
|
||||
bool changed = false;
|
||||
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||
|
||||
for (int location = 0; location < state.Length; location++)
|
||||
{
|
||||
VertexAttribType type = state[location].UnpackType();
|
||||
|
||||
AttributeType value = type switch
|
||||
{
|
||||
VertexAttribType.Sint => AttributeType.Sint,
|
||||
VertexAttribType.Uint => AttributeType.Uint,
|
||||
_ => AttributeType.Float
|
||||
};
|
||||
|
||||
if (attributeTypes[location] != value)
|
||||
{
|
||||
attributeTypes[location] = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetHasConstantBufferDrawParameters(bool value)
|
||||
{
|
||||
if (value != _graphics.HasConstantBufferDrawParameters)
|
||||
{
|
||||
_graphics.HasConstantBufferDrawParameters = value;
|
||||
|
||||
if (_usesDrawParameters)
|
||||
{
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that any storage buffer use is unaligned.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value</param>
|
||||
public void SetHasUnalignedStorageBuffer(bool value)
|
||||
{
|
||||
if (value != _graphics.HasUnalignedStorageBuffer)
|
||||
{
|
||||
_graphics.HasUnalignedStorageBuffer = value;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the GPU pool state.
|
||||
/// </summary>
|
||||
/// <param name="state">The new state</param>
|
||||
public void SetPoolState(GpuChannelPoolState state)
|
||||
{
|
||||
if (!state.Equals(_pool))
|
||||
{
|
||||
_pool = state;
|
||||
|
||||
Signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <summary>
|
||||
/// State update callback entry, with the callback function and associated field names.
|
||||
/// </summary>
|
||||
struct StateUpdateCallbackEntry
|
||||
readonly struct StateUpdateCallbackEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback function, to be called if the register was written as the state needs to be updated.
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
@@ -16,9 +17,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
class StateUpdater
|
||||
{
|
||||
public const int ShaderStateIndex = 16;
|
||||
public const int ShaderStateIndex = 26;
|
||||
public const int RasterizerStateIndex = 15;
|
||||
public const int ScissorStateIndex = 18;
|
||||
public const int ScissorStateIndex = 16;
|
||||
public const int VertexBufferStateIndex = 0;
|
||||
public const int PrimitiveRestartStateIndex = 12;
|
||||
|
||||
@@ -31,6 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
private readonly ShaderProgramInfo[] _currentProgramInfo;
|
||||
private ShaderSpecializationState _shaderSpecState;
|
||||
private SpecializationStateUpdater _currentSpecState;
|
||||
|
||||
private ProgramPipelineState _pipeline;
|
||||
|
||||
@@ -54,15 +56,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">3D engine state</param>
|
||||
/// <param name="drawState">Draw state</param>
|
||||
public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
|
||||
/// <param name="spec">Specialization state updater</param>
|
||||
public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState, SpecializationStateUpdater spec)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
_drawState = drawState;
|
||||
_currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
|
||||
_currentSpecState = spec;
|
||||
|
||||
// ShaderState must be updated after other state updates, as pipeline state is sent to the backend when compiling new shaders.
|
||||
// ShaderState must be updated after other state updates, as specialization/pipeline state is used when fetching shaders.
|
||||
// Render target state must appear after shader state as it depends on information from the currently bound shader.
|
||||
// Rasterizer and scissor states are checked by render target clear, their indexes
|
||||
// must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
|
||||
@@ -101,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
nameof(ThreedClassState.DepthTestFunc)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateTessellationState,
|
||||
nameof(ThreedClassState.TessMode),
|
||||
nameof(ThreedClassState.TessOuterLevel),
|
||||
nameof(ThreedClassState.TessInnerLevel),
|
||||
nameof(ThreedClassState.PatchVertices)),
|
||||
@@ -138,17 +143,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateShaderState,
|
||||
nameof(ThreedClassState.ShaderBaseAddress),
|
||||
nameof(ThreedClassState.ShaderState)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateRenderTargetState,
|
||||
nameof(ThreedClassState.RtColorState),
|
||||
nameof(ThreedClassState.RtDepthStencilState),
|
||||
nameof(ThreedClassState.RtControl),
|
||||
nameof(ThreedClassState.RtDepthStencilSize),
|
||||
nameof(ThreedClassState.RtDepthStencilEnable)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateScissorState,
|
||||
nameof(ThreedClassState.ScissorState),
|
||||
nameof(ThreedClassState.ScreenScissorState)),
|
||||
@@ -179,7 +173,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateMultisampleState,
|
||||
nameof(ThreedClassState.AlphaToCoverageDitherEnable),
|
||||
nameof(ThreedClassState.MultisampleControl))
|
||||
nameof(ThreedClassState.MultisampleControl)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateEarlyZState,
|
||||
nameof(ThreedClassState.EarlyZForce)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateShaderState,
|
||||
nameof(ThreedClassState.ShaderBaseAddress),
|
||||
nameof(ThreedClassState.ShaderState)),
|
||||
|
||||
new StateUpdateCallbackEntry(UpdateRenderTargetState,
|
||||
nameof(ThreedClassState.RtColorState),
|
||||
nameof(ThreedClassState.RtDepthStencilState),
|
||||
nameof(ThreedClassState.RtControl),
|
||||
nameof(ThreedClassState.RtDepthStencilSize),
|
||||
nameof(ThreedClassState.RtDepthStencilEnable)),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -209,17 +217,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Update()
|
||||
{
|
||||
// If any state that the shader depends on changed,
|
||||
// then we may need to compile/bind a different version
|
||||
// of the shader for the new state.
|
||||
if (_shaderSpecState != null)
|
||||
{
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||
{
|
||||
ForceShaderUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// The vertex buffer size is calculated using a different
|
||||
// method when doing indexed draws, so we need to make sure
|
||||
// to update the vertex buffers if we are doing a regular
|
||||
@@ -271,6 +268,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_updateTracker.Update(ulong.MaxValue);
|
||||
|
||||
// If any state that the shader depends on changed,
|
||||
// then we may need to compile/bind a different version
|
||||
// of the shader for the new state.
|
||||
if (_shaderSpecState != null && _currentSpecState.HasChanged())
|
||||
{
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||
{
|
||||
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
||||
UpdateShaderState();
|
||||
}
|
||||
}
|
||||
|
||||
CommitBindings();
|
||||
|
||||
if (tfEnable && !_prevTfEnable)
|
||||
@@ -302,7 +311,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
if (!_channel.TextureManager.CommitGraphicsBindings(_shaderSpecState) || (buffers.HasUnalignedStorageBuffers != hasUnaligned))
|
||||
{
|
||||
// Shader must be reloaded.
|
||||
_currentSpecState.SetHasUnalignedStorageBuffer(buffers.HasUnalignedStorageBuffers);
|
||||
// Shader must be reloaded. _vtgWritesRtLayer should not change.
|
||||
UpdateShaderState();
|
||||
}
|
||||
|
||||
@@ -351,6 +361,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.PatchVertices,
|
||||
_state.State.TessOuterLevel.AsSpan(),
|
||||
_state.State.TessInnerLevel.AsSpan());
|
||||
|
||||
_currentSpecState.SetTessellationMode(_state.State.TessMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -611,6 +623,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestRef,
|
||||
_state.State.AlphaTestFunc);
|
||||
|
||||
_currentSpecState.SetAlphaTest(
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestRef,
|
||||
_state.State.AlphaTestFunc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -710,6 +727,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_context.Renderer.Pipeline.SetDepthMode(GetDepthMode());
|
||||
_context.Renderer.Pipeline.SetViewports(viewports, disableTransform);
|
||||
|
||||
_currentSpecState.SetViewportTransformDisable(_state.State.ViewportTransformEnable == 0);
|
||||
_currentSpecState.SetDepthMode(GetDepthMode() == DepthMode.MinusOneToOne);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -847,6 +867,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
|
||||
_channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex);
|
||||
|
||||
_currentSpecState.SetPoolState(GetPoolState());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -887,6 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -914,6 +937,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
|
||||
|
||||
_context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
|
||||
|
||||
_currentSpecState.SetProgramPointSizeEnable(isProgramPointSize);
|
||||
_currentSpecState.SetPointSize(size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1212,6 +1238,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
alphaToCoverageEnable,
|
||||
_state.State.AlphaToCoverageDitherEnable,
|
||||
alphaToOneEnable));
|
||||
|
||||
_currentSpecState.SetAlphaToCoverageEnable(alphaToCoverageEnable, _state.State.AlphaToCoverageDitherEnable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the early z flag, based on guest state.
|
||||
/// </summary>
|
||||
private void UpdateEarlyZState()
|
||||
{
|
||||
_currentSpecState.SetEarlyZForce(_state.State.EarlyZForce);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1239,10 +1275,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
addressesSpan[index] = baseAddress + shader.Offset;
|
||||
}
|
||||
|
||||
GpuChannelPoolState poolState = GetPoolState();
|
||||
GpuChannelGraphicsState graphicsState = GetGraphicsState();
|
||||
CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, ref _currentSpecState.GetPoolState(), ref _currentSpecState.GetGraphicsState(), addresses);
|
||||
|
||||
CachedShaderProgram gs = shaderCache.GetGraphicsShader(ref _state.State, ref _pipeline, _channel, poolState, graphicsState, addresses);
|
||||
// Consume the modified flag for spec state so that it isn't checked again.
|
||||
_currentSpecState.SetShader(gs);
|
||||
|
||||
_shaderSpecState = gs.SpecializationState;
|
||||
|
||||
@@ -1257,88 +1293,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
UpdateUserClipState();
|
||||
}
|
||||
|
||||
UpdateShaderBindings(gs.Bindings);
|
||||
|
||||
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
||||
{
|
||||
UpdateStageBindings(stageIndex, gs.Shaders[stageIndex + 1]?.Info);
|
||||
_currentProgramInfo[stageIndex] = gs.Shaders[stageIndex + 1]?.Info;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates bindings consumed by the shader stage on the texture and buffer managers.
|
||||
/// Updates bindings consumed by the shader on the texture and buffer managers.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage to have the bindings updated</param>
|
||||
/// <param name="info">Shader stage bindings info</param>
|
||||
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
private void UpdateShaderBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
_currentProgramInfo[stage] = info;
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
_channel.TextureManager.RentGraphicsTextureBindings(stage, 0);
|
||||
_channel.TextureManager.RentGraphicsImageBindings(stage, 0);
|
||||
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
|
||||
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
|
||||
return;
|
||||
}
|
||||
|
||||
int maxTextureBinding = -1;
|
||||
int maxImageBinding = -1;
|
||||
|
||||
Span<TextureBindingInfo> textureBindings = _channel.TextureManager.RentGraphicsTextureBindings(stage, info.Textures.Count);
|
||||
|
||||
if (info.UsesRtLayer)
|
||||
{
|
||||
_vtgWritesRtLayer = true;
|
||||
}
|
||||
|
||||
for (int index = 0; index < info.Textures.Count; index++)
|
||||
{
|
||||
var descriptor = info.Textures[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
|
||||
textureBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxTextureBinding)
|
||||
{
|
||||
maxTextureBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
TextureBindingInfo[] imageBindings = _channel.TextureManager.RentGraphicsImageBindings(stage, info.Images.Count);
|
||||
|
||||
for (int index = 0; index < info.Images.Count; index++)
|
||||
{
|
||||
var descriptor = info.Images[index];
|
||||
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
|
||||
imageBindings[index] = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxImageBinding)
|
||||
{
|
||||
maxImageBinding = descriptor.Binding;
|
||||
}
|
||||
}
|
||||
|
||||
_channel.TextureManager.SetGraphicsMaxBindings(maxTextureBinding, maxImageBinding);
|
||||
|
||||
_channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
|
||||
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
|
||||
_channel.TextureManager.SetGraphicsBindings(bindings);
|
||||
_channel.BufferManager.SetGraphicsBufferBindings(bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1353,46 +1325,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
(int)_state.State.TextureBufferIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current GPU channel state for shader creation or compatibility verification.
|
||||
/// </summary>
|
||||
/// <returns>Current GPU channel state</returns>
|
||||
private GpuChannelGraphicsState GetGraphicsState()
|
||||
{
|
||||
ref var vertexAttribState = ref _state.State.VertexAttribState;
|
||||
|
||||
Array32<AttributeType> attributeTypes = new Array32<AttributeType>();
|
||||
|
||||
for (int location = 0; location < attributeTypes.Length; location++)
|
||||
{
|
||||
VertexAttribType type = vertexAttribState[location].UnpackType();
|
||||
|
||||
attributeTypes[location] = type switch
|
||||
{
|
||||
VertexAttribType.Sint => AttributeType.Sint,
|
||||
VertexAttribType.Uint => AttributeType.Uint,
|
||||
_ => AttributeType.Float
|
||||
};
|
||||
}
|
||||
|
||||
return new GpuChannelGraphicsState(
|
||||
_state.State.EarlyZForce,
|
||||
_drawState.Topology,
|
||||
_state.State.TessMode,
|
||||
(_state.State.MultisampleControl & 1) != 0,
|
||||
_state.State.AlphaToCoverageDitherEnable,
|
||||
_state.State.ViewportTransformEnable == 0,
|
||||
GetDepthMode() == DepthMode.MinusOneToOne,
|
||||
_state.State.VertexProgramPointSize,
|
||||
_state.State.PointSize,
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestFunc,
|
||||
_state.State.AlphaTestRef,
|
||||
ref attributeTypes,
|
||||
_drawState.HasConstantBufferDrawParameters,
|
||||
_channel.BufferManager.HasUnalignedStorageBuffers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the depth mode that is currently being used (zero to one or minus one to one).
|
||||
/// </summary>
|
||||
|
@@ -67,12 +67,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
|
||||
|
||||
var spec = new SpecializationStateUpdater();
|
||||
var drawState = new DrawState();
|
||||
|
||||
_drawManager = new DrawManager(context, channel, _state, drawState);
|
||||
_drawManager = new DrawManager(context, channel, _state, drawState, spec);
|
||||
_semaphoreUpdater = new SemaphoreUpdater(context, channel, _state);
|
||||
_cbUpdater = new ConstantBufferUpdater(channel, _state);
|
||||
_stateUpdater = new StateUpdater(context, channel, _state, drawState);
|
||||
_stateUpdater = new StateUpdater(context, channel, _state, drawState, spec);
|
||||
|
||||
// This defaults to "always", even without any register write.
|
||||
// Reads just return 0, regardless of what was set there.
|
||||
|
@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <summary>
|
||||
/// Represents texture format information.
|
||||
/// </summary>
|
||||
struct FormatInfo
|
||||
readonly struct FormatInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// A default, generic RGBA8 texture format.
|
||||
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// Texture binding information.
|
||||
/// This is used for textures that needs to be accessed from shaders.
|
||||
/// </summary>
|
||||
struct TextureBindingInfo
|
||||
readonly struct TextureBindingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Shader sampler target type.
|
||||
|
@@ -37,8 +37,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private TexturePool _cachedTexturePool;
|
||||
private SamplerPool _cachedSamplerPool;
|
||||
|
||||
private readonly TextureBindingInfo[][] _textureBindings;
|
||||
private readonly TextureBindingInfo[][] _imageBindings;
|
||||
private TextureBindingInfo[][] _textureBindings;
|
||||
private TextureBindingInfo[][] _imageBindings;
|
||||
|
||||
private struct TextureState
|
||||
{
|
||||
@@ -56,9 +56,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private TextureState[] _textureState;
|
||||
private TextureState[] _imageState;
|
||||
|
||||
private int[] _textureBindingsCount;
|
||||
private int[] _imageBindingsCount;
|
||||
|
||||
private int _texturePoolSequence;
|
||||
private int _samplerPoolSequence;
|
||||
|
||||
@@ -101,9 +98,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_textureState = new TextureState[InitialTextureStateSize];
|
||||
_imageState = new TextureState[InitialImageStateSize];
|
||||
|
||||
_textureBindingsCount = new int[stages];
|
||||
_imageBindingsCount = new int[stages];
|
||||
|
||||
for (int stage = 0; stage < stages; stage++)
|
||||
{
|
||||
_textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize];
|
||||
@@ -112,39 +106,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the texture bindings array for a given stage, so that they can be modified.
|
||||
/// Sets the texture and image bindings.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The texture bindings array</returns>
|
||||
public TextureBindingInfo[] RentTextureBindings(int stage, int count)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
if (count > _textureBindings[stage].Length)
|
||||
{
|
||||
Array.Resize(ref _textureBindings[stage], count);
|
||||
}
|
||||
_textureBindings = bindings.TextureBindings;
|
||||
_imageBindings = bindings.ImageBindings;
|
||||
|
||||
_textureBindingsCount[stage] = count;
|
||||
|
||||
return _textureBindings[stage];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the image bindings array for a given stage, so that they can be modified.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage number, or 0 for compute shaders</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The image bindings array</returns>
|
||||
public TextureBindingInfo[] RentImageBindings(int stage, int count)
|
||||
{
|
||||
if (count > _imageBindings[stage].Length)
|
||||
{
|
||||
Array.Resize(ref _imageBindings[stage], count);
|
||||
}
|
||||
|
||||
_imageBindingsCount[stage] = count;
|
||||
|
||||
return _imageBindings[stage];
|
||||
SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -257,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
case ShaderStage.Vertex:
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
index += _textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex];
|
||||
index += _textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length;
|
||||
|
||||
result = texture.ScaleFactor;
|
||||
break;
|
||||
@@ -284,7 +254,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
private bool VertexRequiresScale()
|
||||
{
|
||||
for (int i = 0; i < _textureBindingsCount[0]; i++)
|
||||
for (int i = 0; i < _textureBindings[0].Length; i++)
|
||||
{
|
||||
if ((_textureBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
|
||||
{
|
||||
@@ -292,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _imageBindingsCount[0]; i++)
|
||||
for (int i = 0; i < _imageBindings[0].Length; i++)
|
||||
{
|
||||
if ((_imageBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
|
||||
{
|
||||
@@ -309,10 +279,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
private void CommitRenderScale()
|
||||
{
|
||||
// Stage 0 total: Compute or Vertex.
|
||||
int total = _textureBindingsCount[0] + _imageBindingsCount[0];
|
||||
int total = _textureBindings[0].Length + _imageBindings[0].Length;
|
||||
|
||||
int fragmentIndex = (int)ShaderStage.Fragment - 1;
|
||||
int fragmentTotal = _isCompute ? 0 : (_textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex]);
|
||||
int fragmentTotal = _isCompute ? 0 : (_textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length);
|
||||
|
||||
if (total != 0 && fragmentTotal != _lastFragmentTotal && VertexRequiresScale())
|
||||
{
|
||||
@@ -481,7 +451,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
bool poolModified,
|
||||
ShaderSpecializationState specState)
|
||||
{
|
||||
int textureCount = _textureBindingsCount[stageIndex];
|
||||
int textureCount = _textureBindings[stageIndex].Length;
|
||||
if (textureCount == 0)
|
||||
{
|
||||
return true;
|
||||
@@ -609,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <returns>True if all bound images match the current shader specialiation state, false otherwise</returns>
|
||||
private bool CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex, bool poolModified, ShaderSpecializationState specState)
|
||||
{
|
||||
int imageCount = _imageBindingsCount[stageIndex];
|
||||
int imageCount = _imageBindings[stageIndex].Length;
|
||||
if (imageCount == 0)
|
||||
{
|
||||
return true;
|
||||
@@ -622,7 +592,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
// Scales for images appear after the texture ones.
|
||||
int baseScaleIndex = _textureBindingsCount[stageIndex];
|
||||
int baseScaleIndex = _textureBindings[stageIndex].Length;
|
||||
|
||||
int cachedTextureBufferIndex = -1;
|
||||
int cachedSamplerBufferIndex = -1;
|
||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// </summary>
|
||||
class TextureCache : IDisposable
|
||||
{
|
||||
private struct OverlapInfo
|
||||
private readonly struct OverlapInfo
|
||||
{
|
||||
public TextureViewCompatibility Compatibility { get; }
|
||||
public int FirstLayer { get; }
|
||||
@@ -1088,10 +1088,9 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
{
|
||||
FormatInfo formatInfo = TextureCompatibility.ToHostCompatibleFormat(info, caps);
|
||||
|
||||
if (info.Target == Target.TextureBuffer)
|
||||
if (info.Target == Target.TextureBuffer && !caps.SupportsSnormBufferTextureFormat)
|
||||
{
|
||||
// We assume that the host does not support signed normalized format
|
||||
// (as is the case with OpenGL), so we just use a unsigned format.
|
||||
// If the host does not support signed normalized formats, we use a signed integer format instead.
|
||||
// The shader will need the appropriate conversion code to compensate.
|
||||
switch (formatInfo.Format)
|
||||
{
|
||||
|
@@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <summary>
|
||||
/// An overlapping texture group with a given view compatibility.
|
||||
/// </summary>
|
||||
struct TextureIncompatibleOverlap
|
||||
readonly struct TextureIncompatibleOverlap
|
||||
{
|
||||
public readonly TextureGroup Group;
|
||||
public readonly TextureViewCompatibility Compatibility;
|
||||
|
@@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <summary>
|
||||
/// Texture information.
|
||||
/// </summary>
|
||||
struct TextureInfo
|
||||
readonly struct TextureInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Address of the texture in GPU mapped memory.
|
||||
|
@@ -57,45 +57,21 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the texture bindings array of the compute pipeline.
|
||||
/// Sets the texture and image bindings for the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The texture bindings array</returns>
|
||||
public TextureBindingInfo[] RentComputeTextureBindings(int count)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetComputeBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
return _cpBindingsManager.RentTextureBindings(0, count);
|
||||
_cpBindingsManager.SetBindings(bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the texture bindings array for a given stage on the graphics pipeline.
|
||||
/// Sets the texture and image bindings for the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">The index of the shader stage to bind the textures</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The texture bindings array</returns>
|
||||
public TextureBindingInfo[] RentGraphicsTextureBindings(int stage, int count)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetGraphicsBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
return _gpBindingsManager.RentTextureBindings(stage, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the image bindings array of the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The image bindings array</returns>
|
||||
public TextureBindingInfo[] RentComputeImageBindings(int count)
|
||||
{
|
||||
return _cpBindingsManager.RentImageBindings(0, count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents the image bindings array for a given stage on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">The index of the shader stage to bind the images</param>
|
||||
/// <param name="count">The number of bindings needed</param>
|
||||
/// <returns>The image bindings array</returns>
|
||||
public TextureBindingInfo[] RentGraphicsImageBindings(int stage, int count)
|
||||
{
|
||||
return _gpBindingsManager.RentImageBindings(stage, count);
|
||||
_gpBindingsManager.SetBindings(bindings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,16 +83,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_cpBindingsManager.SetTextureBufferIndex(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the max binding indexes on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="maxTextureBinding">The maximum texture binding</param>
|
||||
/// <param name="maxImageBinding">The maximum image binding</param>
|
||||
public void SetComputeMaxBindings(int maxTextureBinding, int maxImageBinding)
|
||||
{
|
||||
_cpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture constant buffer index on the graphics pipeline.
|
||||
/// </summary>
|
||||
@@ -126,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_gpBindingsManager.SetTextureBufferIndex(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the max binding indexes on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="maxTextureBinding">The maximum texture binding</param>
|
||||
/// <param name="maxImageBinding">The maximum image binding</param>
|
||||
public void SetGraphicsMaxBindings(int maxTextureBinding, int maxImageBinding)
|
||||
{
|
||||
_gpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current sampler pool on the compute pipeline.
|
||||
/// </summary>
|
||||
|
@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Memory range used for buffers.
|
||||
/// </summary>
|
||||
struct BufferBounds
|
||||
readonly struct BufferBounds
|
||||
{
|
||||
/// <summary>
|
||||
/// Region virtual address.
|
||||
|
@@ -1,10 +1,10 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Shader buffer binding information.
|
||||
/// </summary>
|
||||
public BufferDescriptor[] Bindings { get; }
|
||||
public BufferDescriptor[] Bindings { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Buffer regions.
|
||||
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Sets shader buffer binding information.
|
||||
/// </summary>
|
||||
/// <param name="descriptors">Buffer binding information</param>
|
||||
public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
public void SetBindings(BufferDescriptor[] descriptors)
|
||||
{
|
||||
if (descriptors == null)
|
||||
{
|
||||
@@ -86,8 +86,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
return;
|
||||
}
|
||||
|
||||
descriptors.CopyTo(Bindings, 0);
|
||||
Count = descriptors.Count;
|
||||
if ((Count = descriptors.Length) != 0)
|
||||
{
|
||||
Bindings = descriptors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,41 +322,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Sets the binding points for the storage buffers bound on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetComputeBufferBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
_cpStorageBuffers.SetBindings(descriptors);
|
||||
_cpStorageBuffers.SetBindings(bindings.StorageBufferBindings[0]);
|
||||
_cpUniformBuffers.SetBindings(bindings.ConstantBufferBindings[0]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the binding points for the storage buffers bound on the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="stage">Index of the shader stage</param>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
/// <param name="bindings">Bindings for the active shader</param>
|
||||
public void SetGraphicsBufferBindings(CachedShaderBindings bindings)
|
||||
{
|
||||
_gpStorageBuffers[stage].SetBindings(descriptors);
|
||||
for (int i = 0; i < Constants.ShaderStages; i++)
|
||||
{
|
||||
_gpStorageBuffers[i].SetBindings(bindings.StorageBufferBindings[i]);
|
||||
_gpUniformBuffers[i].SetBindings(bindings.ConstantBufferBindings[i]);
|
||||
}
|
||||
|
||||
_gpStorageBuffersDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the binding points for the uniform buffers bound on the compute pipeline.
|
||||
/// </summary>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
{
|
||||
_cpUniformBuffers.SetBindings(descriptors);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the enabled uniform buffers mask on the graphics pipeline.
|
||||
/// Each bit set on the mask indicates that the respective buffer index is enabled.
|
||||
/// </summary>
|
||||
/// <param name="stage">Index of the shader stage</param>
|
||||
/// <param name="descriptors">Buffer descriptors with the binding point values</param>
|
||||
public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors)
|
||||
{
|
||||
_gpUniformBuffers[stage].SetBindings(descriptors);
|
||||
_gpUniformBuffersDirty = true;
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// A buffer binding to apply to a buffer texture.
|
||||
/// </summary>
|
||||
struct BufferTextureBinding
|
||||
readonly struct BufferTextureBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Shader stage accessing the texture.
|
||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// </summary>
|
||||
class CounterCache
|
||||
{
|
||||
private struct CounterEntry
|
||||
private readonly struct CounterEntry
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public ICounterEvent Event { get; }
|
||||
|
103
Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs
Normal file
103
Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of shader bindings ready for insertion into the buffer and texture managers.
|
||||
/// </summary>
|
||||
internal class CachedShaderBindings
|
||||
{
|
||||
public TextureBindingInfo[][] TextureBindings { get; }
|
||||
public TextureBindingInfo[][] ImageBindings { get; }
|
||||
public BufferDescriptor[][] ConstantBufferBindings { get; }
|
||||
public BufferDescriptor[][] StorageBufferBindings { get; }
|
||||
|
||||
public int MaxTextureBinding { get; }
|
||||
public int MaxImageBinding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new cached shader bindings collection.
|
||||
/// </summary>
|
||||
/// <param name="isCompute">Whether the shader is for compute</param>
|
||||
/// <param name="stages">The stages used by the shader</param>
|
||||
public CachedShaderBindings(bool isCompute, CachedShaderStage[] stages)
|
||||
{
|
||||
int stageCount = isCompute ? 1 : Constants.ShaderStages;
|
||||
|
||||
TextureBindings = new TextureBindingInfo[stageCount][];
|
||||
ImageBindings = new TextureBindingInfo[stageCount][];
|
||||
ConstantBufferBindings = new BufferDescriptor[stageCount][];
|
||||
StorageBufferBindings = new BufferDescriptor[stageCount][];
|
||||
|
||||
int maxTextureBinding = -1;
|
||||
int maxImageBinding = -1;
|
||||
int offset = isCompute ? 0 : 1;
|
||||
|
||||
for (int i = 0; i < stageCount; i++)
|
||||
{
|
||||
CachedShaderStage stage = stages[i + offset];
|
||||
|
||||
if (stage == null)
|
||||
{
|
||||
TextureBindings[i] = Array.Empty<TextureBindingInfo>();
|
||||
ImageBindings[i] = Array.Empty<TextureBindingInfo>();
|
||||
ConstantBufferBindings[i] = Array.Empty<BufferDescriptor>();
|
||||
StorageBufferBindings[i] = Array.Empty<BufferDescriptor>();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
TextureBindings[i] = stage.Info.Textures.Select(descriptor =>
|
||||
{
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxTextureBinding)
|
||||
{
|
||||
maxTextureBinding = descriptor.Binding;
|
||||
}
|
||||
|
||||
return result;
|
||||
}).ToArray();
|
||||
|
||||
ImageBindings[i] = stage.Info.Images.Select(descriptor =>
|
||||
{
|
||||
Target target = ShaderTexture.GetTarget(descriptor.Type);
|
||||
Format format = ShaderTexture.GetFormat(descriptor.Format);
|
||||
|
||||
var result = new TextureBindingInfo(
|
||||
target,
|
||||
format,
|
||||
descriptor.Binding,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Flags);
|
||||
|
||||
if (descriptor.Binding > maxImageBinding)
|
||||
{
|
||||
maxImageBinding = descriptor.Binding;
|
||||
}
|
||||
|
||||
return result;
|
||||
}).ToArray();
|
||||
|
||||
ConstantBufferBindings[i] = stage.Info.CBuffers.ToArray();
|
||||
StorageBufferBindings[i] = stage.Info.SBuffers.ToArray();
|
||||
}
|
||||
|
||||
MaxTextureBinding = maxTextureBinding;
|
||||
MaxImageBinding = maxImageBinding;
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,6 +24,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
public CachedShaderStage[] Shaders { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Cached shader bindings, ready for placing into the bindings manager.
|
||||
/// </summary>
|
||||
public CachedShaderBindings Bindings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the shader bundle.
|
||||
/// </summary>
|
||||
@@ -37,6 +42,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
Shaders = shaders;
|
||||
|
||||
SpecializationState.Prepare(shaders);
|
||||
Bindings = new CachedShaderBindings(shaders.Length == 1, shaders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <summary>
|
||||
/// Represents an operation to perform on the <see cref="_fileWriterWorkerQueue"/>.
|
||||
/// </summary>
|
||||
private struct CacheFileOperationTask
|
||||
private readonly struct CacheFileOperationTask
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of operation to perform.
|
||||
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <summary>
|
||||
/// Background shader cache write information.
|
||||
/// </summary>
|
||||
private struct AddShaderData
|
||||
private readonly struct AddShaderData
|
||||
{
|
||||
/// <summary>
|
||||
/// Cached shader program.
|
||||
|
@@ -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 = 3943;
|
||||
private const uint CodeGenVersion = 4011;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <summary>
|
||||
/// Guest shader code and constant buffer data accessed by the shader.
|
||||
/// </summary>
|
||||
struct GuestCodeAndCbData
|
||||
readonly struct GuestCodeAndCbData
|
||||
{
|
||||
/// <summary>
|
||||
/// Maxwell binary shader code.
|
||||
|
@@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <summary>
|
||||
/// Program validation entry.
|
||||
/// </summary>
|
||||
private struct ProgramEntry
|
||||
private readonly struct ProgramEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Cached shader program.
|
||||
@@ -90,7 +90,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <summary>
|
||||
/// Translated shader compilation entry.
|
||||
/// </summary>
|
||||
private struct ProgramCompilation
|
||||
private readonly struct ProgramCompilation
|
||||
{
|
||||
/// <summary>
|
||||
/// Translated shader stages.
|
||||
@@ -143,7 +143,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
/// <summary>
|
||||
/// Program translation entry.
|
||||
/// </summary>
|
||||
private struct AsyncProgramTranslation
|
||||
private readonly struct AsyncProgramTranslation
|
||||
{
|
||||
/// <summary>
|
||||
/// Guest code for each active stage.
|
||||
|
@@ -134,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
|
||||
|
||||
public bool QueryHostSupportsSnormBufferTextureFormat() => _context.Capabilities.SupportsSnormBufferTextureFormat;
|
||||
|
||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||
|
||||
public bool QueryHostSupportsViewportIndex() => _context.Capabilities.SupportsViewportIndex;
|
||||
|
@@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// State used by the <see cref="GpuAccessor"/>.
|
||||
/// </summary>
|
||||
struct GpuChannelComputeState
|
||||
readonly struct GpuChannelComputeState
|
||||
{
|
||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||
|
||||
|
@@ -15,62 +15,62 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Early Z force enable.
|
||||
/// </summary>
|
||||
public readonly bool EarlyZForce;
|
||||
public bool EarlyZForce;
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology of current draw.
|
||||
/// </summary>
|
||||
public readonly PrimitiveTopology Topology;
|
||||
public PrimitiveTopology Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Tessellation mode.
|
||||
/// </summary>
|
||||
public readonly TessMode TessellationMode;
|
||||
public TessMode TessellationMode;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether alpha-to-coverage is enabled.
|
||||
/// </summary>
|
||||
public readonly bool AlphaToCoverageEnable;
|
||||
public bool AlphaToCoverageEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether alpha-to-coverage dithering is enabled.
|
||||
/// </summary>
|
||||
public readonly bool AlphaToCoverageDitherEnable;
|
||||
public bool AlphaToCoverageDitherEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the viewport transform is disabled.
|
||||
/// </summary>
|
||||
public readonly bool ViewportTransformDisable;
|
||||
public bool ViewportTransformDisable;
|
||||
|
||||
/// <summary>
|
||||
/// Depth mode zero to one or minus one to one.
|
||||
/// </summary>
|
||||
public readonly bool DepthMode;
|
||||
public bool DepthMode;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the point size is set on the shader or is fixed.
|
||||
/// </summary>
|
||||
public readonly bool ProgramPointSizeEnable;
|
||||
public bool ProgramPointSizeEnable;
|
||||
|
||||
/// <summary>
|
||||
/// Point size used if <see cref="ProgramPointSizeEnable" /> is false.
|
||||
/// </summary>
|
||||
public readonly float PointSize;
|
||||
public float PointSize;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether alpha test is enabled.
|
||||
/// </summary>
|
||||
public readonly bool AlphaTestEnable;
|
||||
public bool AlphaTestEnable;
|
||||
|
||||
/// <summary>
|
||||
/// When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded.
|
||||
/// </summary>
|
||||
public readonly CompareOp AlphaTestCompare;
|
||||
public CompareOp AlphaTestCompare;
|
||||
|
||||
/// <summary>
|
||||
/// When alpha test is enabled, indicates the value to compare with the fragment output alpha.
|
||||
/// </summary>
|
||||
public readonly float AlphaTestReference;
|
||||
public float AlphaTestReference;
|
||||
|
||||
/// <summary>
|
||||
/// Type of the vertex attributes consumed by the shader.
|
||||
@@ -80,12 +80,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
public readonly bool HasConstantBufferDrawParameters;
|
||||
public bool HasConstantBufferDrawParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that any storage buffer use is unaligned.
|
||||
/// </summary>
|
||||
public readonly bool HasUnalignedStorageBuffer;
|
||||
public bool HasUnalignedStorageBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GPU graphics state.
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
/// <summary>
|
||||
/// State used by the <see cref="GpuAccessor"/>.
|
||||
/// </summary>
|
||||
struct GpuChannelPoolState
|
||||
readonly struct GpuChannelPoolState : IEquatable<GpuChannelPoolState>
|
||||
{
|
||||
/// <summary>
|
||||
/// GPU virtual address of the texture pool.
|
||||
@@ -32,5 +34,17 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
TexturePoolMaximumId = texturePoolMaximumId;
|
||||
TextureBufferIndex = textureBufferIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the pool states are equal.
|
||||
/// </summary>
|
||||
/// <param name="other">Pool state to compare with</param>
|
||||
/// <returns>True if they are equal, false otherwise</returns>
|
||||
public bool Equals(GpuChannelPoolState other)
|
||||
{
|
||||
return TexturePoolGpuVa == other.TexturePoolGpuVa &&
|
||||
TexturePoolMaximumId == other.TexturePoolMaximumId &&
|
||||
TextureBufferIndex == other.TextureBufferIndex;
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.HashTable
|
||||
/// <summary>
|
||||
/// Entry for a given data size.
|
||||
/// </summary>
|
||||
private struct SizeEntry
|
||||
private readonly struct SizeEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Size for the data that will be stored on the hash table on this entry.
|
||||
|
@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// </summary>
|
||||
public const TranslationFlags DefaultFlags = TranslationFlags.DebugMode;
|
||||
|
||||
private struct TranslatedShader
|
||||
private readonly struct TranslatedShader
|
||||
{
|
||||
public readonly CachedShaderStage Shader;
|
||||
public readonly ShaderProgram Program;
|
||||
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
}
|
||||
}
|
||||
|
||||
private struct TranslatedShaderVertexPair
|
||||
private readonly struct TranslatedShaderVertexPair
|
||||
{
|
||||
public readonly CachedShaderStage VertexA;
|
||||
public readonly CachedShaderStage VertexB;
|
||||
@@ -59,7 +59,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
private readonly Dictionary<ulong, CachedShaderProgram> _cpPrograms;
|
||||
private readonly Dictionary<ShaderAddresses, CachedShaderProgram> _gpPrograms;
|
||||
|
||||
private struct ProgramToSave
|
||||
private readonly struct ProgramToSave
|
||||
{
|
||||
public readonly CachedShaderProgram CachedProgram;
|
||||
public readonly IProgram HostProgram;
|
||||
@@ -300,16 +300,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
ref ThreedClassState state,
|
||||
ref ProgramPipelineState pipeline,
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
ShaderAddresses addresses)
|
||||
{
|
||||
if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, poolState, graphicsState, gpShaders, addresses))
|
||||
if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses))
|
||||
{
|
||||
return gpShaders;
|
||||
}
|
||||
|
||||
if (_graphicsShaderCache.TryFind(channel, poolState, graphicsState, addresses, out gpShaders, out var cachedGuestCode))
|
||||
if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out var cachedGuestCode))
|
||||
{
|
||||
_gpPrograms[addresses] = gpShaders;
|
||||
return gpShaders;
|
||||
@@ -498,7 +498,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
if (IsShaderEqual(channel.MemoryManager, cpShader.Shaders[0], gpuVa))
|
||||
{
|
||||
return cpShader.SpecializationState.MatchesCompute(channel, poolState, computeState, true);
|
||||
return cpShader.SpecializationState.MatchesCompute(channel, ref poolState, computeState, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -515,8 +515,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if the code is different, false otherwise</returns>
|
||||
private static bool IsShaderEqual(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
CachedShaderProgram gpShaders,
|
||||
ShaderAddresses addresses)
|
||||
{
|
||||
@@ -536,7 +536,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
bool usesDrawParameters = gpShaders.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
|
||||
return gpShaders.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true);
|
||||
return gpShaders.SpecializationState.MatchesGraphics(channel, ref poolState, ref graphicsState, usesDrawParameters, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -215,8 +215,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if a cached host program was found, false otherwise</returns>
|
||||
public bool TryFind(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
ShaderAddresses addresses,
|
||||
out CachedShaderProgram program,
|
||||
out CachedGraphicsGuestCode guestCode)
|
||||
@@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
if (found && _shaderPrograms.TryGetValue(idTable, out ShaderSpecializationList specList))
|
||||
{
|
||||
return specList.TryFindForGraphics(channel, poolState, graphicsState, out program);
|
||||
return specList.TryFindForGraphics(channel, ref poolState, ref graphicsState, out program);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Shader code accessor.
|
||||
/// </summary>
|
||||
struct ShaderCodeAccessor : IDataAccessor
|
||||
readonly struct ShaderCodeAccessor : IDataAccessor
|
||||
{
|
||||
private readonly MemoryManager _memoryManager;
|
||||
private readonly ulong _baseAddress;
|
||||
|
@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Paths where shader code was dumped on disk.
|
||||
/// </summary>
|
||||
struct ShaderDumpPaths
|
||||
readonly struct ShaderDumpPaths
|
||||
{
|
||||
/// <summary>
|
||||
/// Path where the full shader code with header was dumped, or null if not dumped.
|
||||
|
@@ -29,15 +29,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if a compatible program is found, false otherwise</returns>
|
||||
public bool TryFindForGraphics(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
out CachedShaderProgram program)
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
bool usesDrawParameters = entry.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
|
||||
if (entry.SpecializationState.MatchesGraphics(channel, poolState, graphicsState, usesDrawParameters, true))
|
||||
if (entry.SpecializationState.MatchesGraphics(channel, ref poolState, ref graphicsState, usesDrawParameters, true))
|
||||
{
|
||||
program = entry;
|
||||
return true;
|
||||
@@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
foreach (var entry in _entries)
|
||||
{
|
||||
if (entry.SpecializationState.MatchesCompute(channel, poolState, computeState, true))
|
||||
if (entry.SpecializationState.MatchesCompute(channel, ref poolState, computeState, true))
|
||||
{
|
||||
program = entry;
|
||||
return true;
|
||||
|
@@ -121,7 +121,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <summary>
|
||||
/// Texture binding information, used to identify each texture accessed by the shader.
|
||||
/// </summary>
|
||||
private struct TextureKey : IEquatable<TextureKey>
|
||||
private readonly record struct TextureKey
|
||||
{
|
||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||
|
||||
@@ -152,21 +152,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
Handle = handle;
|
||||
CbufSlot = cbufSlot;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is TextureKey textureKey && Equals(textureKey);
|
||||
}
|
||||
|
||||
public bool Equals(TextureKey other)
|
||||
{
|
||||
return StageIndex == other.StageIndex && Handle == other.Handle && CbufSlot == other.CbufSlot;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(StageIndex, Handle, CbufSlot);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<TextureKey, Box<TextureSpecializationState>> _textureSpecialization;
|
||||
@@ -392,6 +377,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
state.Value.QueriedFlags |= QueriedTextureStateFlags.CoordNormalized;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if primitive topology was queried by the shader.
|
||||
/// </summary>
|
||||
/// <returns>True if queried, false otherwise</returns>
|
||||
public bool IsPrimitiveTopologyQueried()
|
||||
{
|
||||
return _queriedState.HasFlag(QueriedStateFlags.PrimitiveTopology);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given texture was registerd on this specialization state.
|
||||
/// </summary>
|
||||
@@ -486,8 +480,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
public bool MatchesGraphics(
|
||||
GpuChannel channel,
|
||||
GpuChannelPoolState poolState,
|
||||
GpuChannelGraphicsState graphicsState,
|
||||
ref GpuChannelPoolState poolState,
|
||||
ref GpuChannelGraphicsState graphicsState,
|
||||
bool usesDrawParameters,
|
||||
bool checkTextures)
|
||||
{
|
||||
@@ -536,7 +530,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, poolState, checkTextures, isCompute: false);
|
||||
return Matches(channel, ref poolState, checkTextures, isCompute: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -547,14 +541,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="computeState">Compute state</param>
|
||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
public bool MatchesCompute(GpuChannel channel, GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
|
||||
public bool MatchesCompute(GpuChannel channel, ref GpuChannelPoolState poolState, GpuChannelComputeState computeState, bool checkTextures)
|
||||
{
|
||||
if (computeState.HasUnalignedStorageBuffer != ComputeState.HasUnalignedStorageBuffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Matches(channel, poolState, checkTextures, isCompute: true);
|
||||
return Matches(channel, ref poolState, checkTextures, isCompute: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -618,7 +612,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="checkTextures">Indicates whether texture descriptors should be checked</param>
|
||||
/// <param name="isCompute">Indicates whenever the check is requested by the 3D or compute engine</param>
|
||||
/// <returns>True if the state matches, false otherwise</returns>
|
||||
private bool Matches(GpuChannel channel, GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
|
||||
private bool Matches(GpuChannel channel, ref GpuChannelPoolState poolState, bool checkTextures, bool isCompute)
|
||||
{
|
||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||
|
||||
|
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// <summary>
|
||||
/// Texture presented on the window.
|
||||
/// </summary>
|
||||
private struct PresentationTexture
|
||||
private readonly struct PresentationTexture
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture cache where the texture might be located.
|
||||
|
@@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Host1x
|
||||
{
|
||||
public sealed class Host1xDevice : IDisposable
|
||||
{
|
||||
private struct Command
|
||||
private readonly struct Command
|
||||
{
|
||||
public int[] Buffer { get; }
|
||||
public long ContextId { get; }
|
||||
|
@@ -7,7 +7,7 @@ namespace Ryujinx.Graphics.Host1x
|
||||
{
|
||||
private readonly SynchronizationManager _syncMgr;
|
||||
|
||||
private struct SyncptIncr
|
||||
private readonly struct SyncptIncr
|
||||
{
|
||||
public uint Id { get; }
|
||||
public ClassId ClassId { get; }
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
public struct FrameDecodedEventArgs
|
||||
public readonly struct FrameDecodedEventArgs
|
||||
{
|
||||
public CodecId CodecId { get; }
|
||||
public uint LumaOffset { get; }
|
||||
|
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.Nvdec.Image;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec
|
||||
{
|
||||
struct ResourceManager
|
||||
readonly struct ResourceManager
|
||||
{
|
||||
public MemoryManager Gmm { get; }
|
||||
public SurfaceCache Cache { get; }
|
||||
|
@@ -2,7 +2,7 @@ using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
struct FormatInfo
|
||||
readonly struct FormatInfo
|
||||
{
|
||||
public int Components { get; }
|
||||
public bool Normalized { get; }
|
||||
|
@@ -113,6 +113,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supports3DTextureCompression: false,
|
||||
supportsBgraFormat: false,
|
||||
supportsR4G4Format: false,
|
||||
supportsSnormBufferTextureFormat: false,
|
||||
supportsFragmentShaderInterlock: HwCapabilities.SupportsFragmentShaderInterlock,
|
||||
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,
|
||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
struct InstInfo
|
||||
readonly struct InstInfo
|
||||
{
|
||||
public InstType Type { get; }
|
||||
|
||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
private static readonly string[] StagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
|
||||
|
||||
private struct BuiltInAttribute
|
||||
private readonly struct BuiltInAttribute
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
|
@@ -3,7 +3,7 @@ using Spv.Generator;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
struct OperationResult
|
||||
readonly struct OperationResult
|
||||
{
|
||||
public static OperationResult Invalid => new OperationResult(AggregateType.Invalid, null);
|
||||
|
||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
/// <summary>
|
||||
/// Delegate cache for SPIR-V instruction generators. Avoids delegate allocation when passing generators as arguments.
|
||||
/// </summary>
|
||||
internal struct SpirvDelegates
|
||||
internal readonly struct SpirvDelegates
|
||||
{
|
||||
// Unary
|
||||
public readonly FuncUnaryInstruction GlslFAbs;
|
||||
|
@@ -1,33 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
struct TextureMeta : IEquatable<TextureMeta>
|
||||
{
|
||||
public int CbufSlot { get; }
|
||||
public int Handle { get; }
|
||||
public TextureFormat Format { get; }
|
||||
|
||||
public TextureMeta(int cbufSlot, int handle, TextureFormat format)
|
||||
{
|
||||
CbufSlot = cbufSlot;
|
||||
Handle = handle;
|
||||
Format = format;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is TextureMeta other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals(TextureMeta other)
|
||||
{
|
||||
return CbufSlot == other.CbufSlot && Handle == other.Handle && Format == other.Format;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(CbufSlot, Handle, Format);
|
||||
}
|
||||
}
|
||||
readonly record struct TextureMeta(int CbufSlot, int Handle, TextureFormat Format);
|
||||
}
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||
}
|
||||
}
|
||||
|
||||
struct SyncTarget
|
||||
readonly struct SyncTarget
|
||||
{
|
||||
public PushOpInfo PushOpInfo { get; }
|
||||
public int PushOpId { get; }
|
||||
|
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Decoders
|
||||
{
|
||||
struct DecodedProgram : IEnumerable<DecodedFunction>
|
||||
readonly struct DecodedProgram : IEnumerable<DecodedFunction>
|
||||
{
|
||||
public DecodedFunction MainFunction { get; }
|
||||
private readonly IReadOnlyDictionary<ulong, DecodedFunction> _functions;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user