Compare commits

..

6 Commits

Author SHA1 Message Date
d7c6474729 GPU: Remove unused dynamic state and pipeline settings (#6796)
* Dynamic state for Depth Bounds should not be passed to PipelineDynamicStateCreateInfo as the command to set them is never called.

Do not pass pointer to viewport and scissor as those dynamic states should be supported on all devices.

Same as above for DepthBias values.

* Code Review Suggestion

* Pipeline derivation is not implemented and is not suggested.

* Depth Bounds are not used.
2024-06-02 22:32:10 -03:00
1ecc8fbc3b New pooled memory types (#6821)
* feat: add new types MemoryOwner and SpanOwner

* use SpanOwner instead of new array allocation

* change for loop condition to `fences.Length` instead of `count` to elide Span boundary checks on `fences`
2024-06-02 22:24:14 -03:00
888402ecaf Avoid inexact read with 'Stream.Read' (#6847) 2024-06-02 22:16:48 +02:00
971d24aef0 nuget: bump Microsoft.IdentityModel.JsonWebTokens from 7.5.2 to 7.6.0 (#6893)
Bumps [Microsoft.IdentityModel.JsonWebTokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 7.5.2 to 7.6.0.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/7.5.2...7.6.0)

---
updated-dependencies:
- dependency-name: Microsoft.IdentityModel.JsonWebTokens
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-02 22:10:47 +02:00
c41fddd25e Vulkan: Extend full bindless to cover cases with phi nodes (#6853)
* Key textures using set and binding (rather than just binding)

* Extend full bindless to cover cases with phi nodes

* Log error on bindless access failure

* Shader cache version bump

* Remove constant buffer match to reduce the chances of full bindless triggering

* Re-enable it for constant buffers, paper mario does actually need it

* Format whitespace
2024-05-26 15:20:10 -03:00
2ebe929fa5 misc: Change disk shader cache compression algorithm to Brotli (RFC 7932) (#6841)
* Prefer `Brotli` compression for disk shader cache.

* Final default case for decompression switch.

* Prefer fastest compression.
2024-05-26 20:06:41 +02:00
18 changed files with 446 additions and 161 deletions

View File

@ -20,7 +20,7 @@
<PackageVersion Include="LibHac" Version="0.19.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.2" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.6.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />

View File

@ -237,7 +237,7 @@ namespace ARMeilleure.CodeGen.Arm64
long originalPosition = _stream.Position;
_stream.Seek(0, SeekOrigin.Begin);
_stream.Read(code, 0, code.Length);
_stream.ReadExactly(code, 0, code.Length);
_stream.Seek(originalPosition, SeekOrigin.Begin);
RelocInfo relocInfo;

View File

@ -1444,7 +1444,7 @@ namespace ARMeilleure.CodeGen.X86
Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
_stream.Read(buffer);
_stream.ReadExactly(buffer);
_stream.Seek(ReservedBytesForJump, SeekOrigin.Current);
codeStream.Write(buffer);

View File

@ -0,0 +1,140 @@
#nullable enable
using System;
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Common.Memory
{
/// <summary>
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
/// </summary>
/// <typeparam name="T">The type of item to store.</typeparam>
public sealed class MemoryOwner<T> : IMemoryOwner<T>
{
private readonly int _length;
private T[]? _array;
/// <summary>
/// Initializes a new instance of the <see cref="MemoryOwner{T}"/> class with the specified parameters.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
private MemoryOwner(int length)
{
_length = length;
_array = ArrayPool<T>.Shared.Rent(length);
}
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified length.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="MemoryOwner{T}"/> instance of the requested length</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> Rent(int length) => new(length);
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified length and the content cleared.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="MemoryOwner{T}"/> instance of the requested length and the content cleared</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> RentCleared(int length)
{
MemoryOwner<T> result = new(length);
result._array.AsSpan(0, length).Clear();
return result;
}
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the content copied from the specified buffer.
/// </summary>
/// <param name="buffer">The buffer to copy</param>
/// <returns>A <see cref="MemoryOwner{T}"/> instance with the same length and content as <paramref name="buffer"/></returns>
public static MemoryOwner<T> RentCopy(ReadOnlySpan<T> buffer)
{
MemoryOwner<T> result = new(buffer.Length);
buffer.CopyTo(result._array);
return result;
}
/// <summary>
/// Gets the number of items in the current instance.
/// </summary>
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _length;
}
/// <inheritdoc/>
public Memory<T> Memory
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
T[]? array = _array;
if (array is null)
{
ThrowObjectDisposedException();
}
return new(array, 0, _length);
}
}
/// <summary>
/// Gets a <see cref="Span{T}"/> wrapping the memory belonging to the current instance.
/// </summary>
/// <remarks>
/// Uses a trick made possible by the .NET 6+ runtime array layout.
/// </remarks>
public Span<T> Span
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
T[]? array = _array;
if (array is null)
{
ThrowObjectDisposedException();
}
ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(array);
return MemoryMarshal.CreateSpan(ref firstElementRef, _length);
}
}
/// <inheritdoc/>
public void Dispose()
{
T[]? array = Interlocked.Exchange(ref _array, null);
if (array is not null)
{
ArrayPool<T>.Shared.Return(array);
}
}
/// <summary>
/// Throws an <see cref="ObjectDisposedException"/> when <see cref="_array"/> is <see langword="null"/>.
/// </summary>
[DoesNotReturn]
private static void ThrowObjectDisposedException()
{
throw new ObjectDisposedException(nameof(MemoryOwner<T>), "The buffer has already been disposed.");
}
}
}

View File

@ -0,0 +1,114 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.Memory
{
/// <summary>
/// A stack-only type that rents a buffer of a specified length from <seealso cref="ArrayPool{T}.Shared"/>.
/// It does not implement <see cref="IDisposable"/> to avoid being boxed, but should still be disposed. This
/// is easy since C# 8, which allows use of C# `using` constructs on any type that has a public Dispose() method.
/// To keep this type simple, fast, and read-only, it does not check or guard against multiple disposals.
/// For all these reasons, all usage should be with a `using` block or statement.
/// </summary>
/// <typeparam name="T">The type of item to store.</typeparam>
public readonly ref struct SpanOwner<T>
{
private readonly int _length;
private readonly T[] _array;
/// <summary>
/// Initializes a new instance of the <see cref="SpanOwner{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
private SpanOwner(int length)
{
_length = length;
_array = ArrayPool<T>.Shared.Rent(length);
}
/// <summary>
/// Gets an empty <see cref="SpanOwner{T}"/> instance.
/// </summary>
public static SpanOwner<T> Empty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(0);
}
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the specified length.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="SpanOwner{T}"/> instance of the requested length</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> Rent(int length) => new(length);
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the length and the content cleared.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="SpanOwner{T}"/> instance of the requested length and the content cleared</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> RentCleared(int length)
{
SpanOwner<T> result = new(length);
result._array.AsSpan(0, length).Clear();
return result;
}
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the content copied from the specified buffer.
/// </summary>
/// <param name="buffer">The buffer to copy</param>
/// <returns>A <see cref="SpanOwner{T}"/> instance with the same length and content as <paramref name="buffer"/></returns>
public static SpanOwner<T> RentCopy(ReadOnlySpan<T> buffer)
{
SpanOwner<T> result = new(buffer.Length);
buffer.CopyTo(result._array);
return result;
}
/// <summary>
/// Gets the number of items in the current instance
/// </summary>
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _length;
}
/// <summary>
/// Gets a <see cref="Span{T}"/> wrapping the memory belonging to the current instance.
/// </summary>
/// <remarks>
/// Uses a trick made possible by the .NET 6+ runtime array layout.
/// </remarks>
public Span<T> Span
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(_array);
return MemoryMarshal.CreateSpan(ref firstElementRef, _length);
}
}
/// <summary>
/// Implements the duck-typed <see cref="IDisposable.Dispose"/> method.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
ArrayPool<T>.Shared.Return(_array);
}
}
}

View File

@ -125,9 +125,18 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
CompressionAlgorithm algorithm = CompressionAlgorithm.None;
Read(ref algorithm);
if (algorithm == CompressionAlgorithm.Deflate)
switch (algorithm)
{
_activeStream = new DeflateStream(_stream, CompressionMode.Decompress, true);
case CompressionAlgorithm.None:
break;
case CompressionAlgorithm.Deflate:
_activeStream = new DeflateStream(_stream, CompressionMode.Decompress, true);
break;
case CompressionAlgorithm.Brotli:
_activeStream = new BrotliStream(_stream, CompressionMode.Decompress, true);
break;
default:
throw new ArgumentException($"Invalid compression algorithm \"{algorithm}\"");
}
}
@ -139,9 +148,18 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
Write(ref algorithm);
if (algorithm == CompressionAlgorithm.Deflate)
switch (algorithm)
{
_activeStream = new DeflateStream(_stream, CompressionLevel.Fastest, true);
case CompressionAlgorithm.None:
break;
case CompressionAlgorithm.Deflate:
_activeStream = new DeflateStream(_stream, CompressionLevel.Fastest, true);
break;
case CompressionAlgorithm.Brotli:
_activeStream = new BrotliStream(_stream, CompressionLevel.Fastest, true);
break;
default:
throw new ArgumentException($"Invalid compression algorithm \"{algorithm}\"");
}
}
@ -177,7 +195,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
switch (algorithm)
{
case CompressionAlgorithm.None:
stream.Read(data);
stream.ReadExactly(data);
break;
case CompressionAlgorithm.Deflate:
stream = new DeflateStream(stream, CompressionMode.Decompress, true);
@ -187,6 +205,14 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
}
stream.Dispose();
break;
case CompressionAlgorithm.Brotli:
stream = new BrotliStream(stream, CompressionMode.Decompress, true);
for (int offset = 0; offset < data.Length;)
{
offset += stream.Read(data[offset..]);
}
stream.Dispose();
break;
}
}
@ -210,6 +236,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
stream.Write(data);
stream.Dispose();
break;
case CompressionAlgorithm.Brotli:
stream = new BrotliStream(stream, CompressionLevel.Fastest, true);
stream.Write(data);
stream.Dispose();
break;
}
}
}

View File

@ -14,5 +14,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
/// Deflate compression (RFC 1951).
/// </summary>
Deflate,
/// <summary>
/// Brotli compression (RFC 7932).
/// </summary>
Brotli,
}
}

View File

@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
/// <returns>Compression algorithm</returns>
public static CompressionAlgorithm GetCompressionAlgorithm()
{
return CompressionAlgorithm.Deflate;
return CompressionAlgorithm.Brotli;
}
}
}

View File

@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
}
dataFileStream.Seek((long)entry.Offset, SeekOrigin.Begin);
dataFileStream.Read(cb1Data);
dataFileStream.ReadExactly(cb1Data);
BinarySerializer.ReadCompressed(dataFileStream, guestCode);
_cache[index] = (guestCode, cb1Data);
@ -279,7 +279,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
dataFileStream.Seek((long)entry.Offset, SeekOrigin.Begin);
byte[] cachedCode = new byte[entry.CodeSize];
byte[] cachedCb1Data = new byte[entry.Cb1DataSize];
dataFileStream.Read(cachedCb1Data);
dataFileStream.ReadExactly(cachedCb1Data);
BinarySerializer.ReadCompressed(dataFileStream, cachedCode);
if (data.SequenceEqual(cachedCode) && cb1Data.SequenceEqual(cachedCb1Data))

View File

@ -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 = 6870;
private const uint CodeGenVersion = 6852;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@ -38,6 +38,12 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// If we can't do bindless elimination, remove the texture operation.
// Set any destination variables to zero.
string typeName = texOp.Inst.IsImage()
? texOp.Type.ToGlslImageType(texOp.Format.GetComponentType())
: texOp.Type.ToGlslTextureType();
gpuAccessor.Log($"Failed to find handle source for bindless access of type \"{typeName}\".");
for (int destIndex = 0; destIndex < texOp.DestsCount; destIndex++)
{
block.Operations.AddBefore(node, new Operation(Instruction.Copy, texOp.GetDest(destIndex), OperandHelper.Const(0)));
@ -62,17 +68,22 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return false;
}
Operand nvHandle = texOp.GetSource(0);
Operand bindlessHandle = texOp.GetSource(0);
if (nvHandle.AsgOp is not Operation handleOp ||
handleOp.Inst != Instruction.Load ||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
if (bindlessHandle.AsgOp is PhiNode phi)
{
// Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
// This is an artificial limitation to prevent it from being used in cases where it
// would have a large performance impact of loading all textures in the pool.
// It might be removed in the future, if we can mitigate the performance impact.
for (int srcIndex = 0; srcIndex < phi.SourcesCount; srcIndex++)
{
Operand phiSource = phi.GetSource(srcIndex);
if (phiSource.AsgOp is not PhiNode && !IsBindlessAccessAllowed(phiSource))
{
return false;
}
}
}
else if (!IsBindlessAccessAllowed(bindlessHandle))
{
return false;
}
@ -80,8 +91,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
Operand samplerHandle = OperandHelper.Local();
Operand textureIndex = OperandHelper.Local();
block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, nvHandle, OperandHelper.Const(0xfffff)));
block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, nvHandle, OperandHelper.Const(20)));
block.Operations.AddBefore(node, new Operation(Instruction.BitwiseAnd, textureHandle, bindlessHandle, OperandHelper.Const(0xfffff)));
block.Operations.AddBefore(node, new Operation(Instruction.ShiftRightU32, samplerHandle, bindlessHandle, OperandHelper.Const(20)));
int texturePoolLength = Math.Max(BindlessToArray.MinimumArrayLength, gpuAccessor.QueryTextureArrayLengthFromPool());
@ -130,6 +141,30 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return true;
}
private static bool IsBindlessAccessAllowed(Operand nvHandle)
{
if (nvHandle.Type == OperandType.ConstantBuffer)
{
// Bindless access with handles from constant buffer is allowed.
return true;
}
if (nvHandle.AsgOp is not Operation handleOp ||
handleOp.Inst != Instruction.Load ||
(handleOp.StorageKind != StorageKind.Input && handleOp.StorageKind != StorageKind.StorageBuffer))
{
// Right now, we only allow bindless access when the handle comes from a shader input or storage buffer.
// This is an artificial limitation to prevent it from being used in cases where it
// would have a large performance impact of loading all textures in the pool.
// It might be removed in the future, if we can mitigate the performance impact.
return false;
}
return true;
}
private static bool TryConvertBindless(BasicBlock block, ResourceManager resourceManager, IGpuAccessor gpuAccessor, TextureOperation texOp)
{
if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())

View File

@ -1,3 +1,4 @@
using Ryujinx.Common.Memory;
using Silk.NET.Vulkan;
using System;
@ -165,14 +166,15 @@ namespace Ryujinx.Graphics.Vulkan
/// <returns>True if all fences were signaled before the timeout expired, false otherwise</returns>
private bool WaitForFencesImpl(Vk api, Device device, int offset, int size, bool hasTimeout, ulong timeout)
{
Span<FenceHolder> fenceHolders = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
using SpanOwner<FenceHolder> fenceHoldersOwner = SpanOwner<FenceHolder>.Rent(CommandBufferPool.MaxCommandBuffers);
Span<FenceHolder> fenceHolders = fenceHoldersOwner.Span;
int count = size != 0 ? GetOverlappingFences(fenceHolders, offset, size) : GetFences(fenceHolders);
Span<Fence> fences = stackalloc Fence[count];
int fenceCount = 0;
for (int i = 0; i < count; i++)
for (int i = 0; i < fences.Length; i++)
{
if (fenceHolders[i].TryGet(out Fence fence))
{

View File

@ -180,9 +180,6 @@ namespace Ryujinx.Graphics.Vulkan
pipeline.LogicOpEnable = state.LogicOpEnable;
pipeline.LogicOp = state.LogicOp.Convert();
pipeline.MinDepthBounds = 0f; // Not implemented.
pipeline.MaxDepthBounds = 0f; // Not implemented.
pipeline.PatchControlPoints = state.PatchControlPoints;
pipeline.PolygonMode = PolygonMode.Fill; // Not implemented.
pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
@ -208,17 +205,11 @@ namespace Ryujinx.Graphics.Vulkan
pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
pipeline.StencilFrontDepthFailOp = state.StencilTest.FrontDpFail.Convert();
pipeline.StencilFrontCompareOp = state.StencilTest.FrontFunc.Convert();
pipeline.StencilFrontCompareMask = 0;
pipeline.StencilFrontWriteMask = 0;
pipeline.StencilFrontReference = 0;
pipeline.StencilBackFailOp = state.StencilTest.BackSFail.Convert();
pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
pipeline.StencilBackCompareMask = 0;
pipeline.StencilBackWriteMask = 0;
pipeline.StencilBackReference = 0;
pipeline.StencilTestEnable = state.StencilTest.TestEnable;

View File

@ -71,244 +71,232 @@ namespace Ryujinx.Graphics.Vulkan
set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32);
}
public float MinDepthBounds
{
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 0) & 0xFFFFFFFF));
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
}
public float MaxDepthBounds
{
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 32) & 0xFFFFFFFF));
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
}
public PolygonMode PolygonMode
{
readonly get => (PolygonMode)((Internal.Id6 >> 0) & 0x3FFFFFFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
readonly get => (PolygonMode)((Internal.Id5 >> 0) & 0x3FFFFFFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
}
public uint StagesCount
{
readonly get => (byte)((Internal.Id6 >> 30) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
readonly get => (byte)((Internal.Id5 >> 30) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
}
public uint VertexAttributeDescriptionsCount
{
readonly get => (byte)((Internal.Id6 >> 38) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
readonly get => (byte)((Internal.Id5 >> 38) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
}
public uint VertexBindingDescriptionsCount
{
readonly get => (byte)((Internal.Id6 >> 46) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
readonly get => (byte)((Internal.Id5 >> 46) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
}
public uint ViewportsCount
{
readonly get => (byte)((Internal.Id6 >> 54) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
readonly get => (byte)((Internal.Id5 >> 54) & 0xFF);
set => Internal.Id5 = (Internal.Id5 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
}
public uint ScissorsCount
{
readonly get => (byte)((Internal.Id7 >> 0) & 0xFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
readonly get => (byte)((Internal.Id6 >> 0) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
}
public uint ColorBlendAttachmentStateCount
{
readonly get => (byte)((Internal.Id7 >> 8) & 0xFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
readonly get => (byte)((Internal.Id6 >> 8) & 0xFF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
}
public PrimitiveTopology Topology
{
readonly get => (PrimitiveTopology)((Internal.Id7 >> 16) & 0xF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
readonly get => (PrimitiveTopology)((Internal.Id6 >> 16) & 0xF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
}
public LogicOp LogicOp
{
readonly get => (LogicOp)((Internal.Id7 >> 20) & 0xF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
readonly get => (LogicOp)((Internal.Id6 >> 20) & 0xF);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
}
public CompareOp DepthCompareOp
{
readonly get => (CompareOp)((Internal.Id7 >> 24) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
readonly get => (CompareOp)((Internal.Id6 >> 24) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
}
public StencilOp StencilFrontFailOp
{
readonly get => (StencilOp)((Internal.Id7 >> 27) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
readonly get => (StencilOp)((Internal.Id6 >> 27) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
}
public StencilOp StencilFrontPassOp
{
readonly get => (StencilOp)((Internal.Id7 >> 30) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
readonly get => (StencilOp)((Internal.Id6 >> 30) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
}
public StencilOp StencilFrontDepthFailOp
{
readonly get => (StencilOp)((Internal.Id7 >> 33) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
readonly get => (StencilOp)((Internal.Id6 >> 33) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
}
public CompareOp StencilFrontCompareOp
{
readonly get => (CompareOp)((Internal.Id7 >> 36) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
readonly get => (CompareOp)((Internal.Id6 >> 36) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
}
public StencilOp StencilBackFailOp
{
readonly get => (StencilOp)((Internal.Id7 >> 39) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
readonly get => (StencilOp)((Internal.Id6 >> 39) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
}
public StencilOp StencilBackPassOp
{
readonly get => (StencilOp)((Internal.Id7 >> 42) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
readonly get => (StencilOp)((Internal.Id6 >> 42) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
}
public StencilOp StencilBackDepthFailOp
{
readonly get => (StencilOp)((Internal.Id7 >> 45) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
readonly get => (StencilOp)((Internal.Id6 >> 45) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
}
public CompareOp StencilBackCompareOp
{
readonly get => (CompareOp)((Internal.Id7 >> 48) & 0x7);
set => Internal.Id7 = (Internal.Id7 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
readonly get => (CompareOp)((Internal.Id6 >> 48) & 0x7);
set => Internal.Id6 = (Internal.Id6 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
}
public CullModeFlags CullMode
{
readonly get => (CullModeFlags)((Internal.Id7 >> 51) & 0x3);
set => Internal.Id7 = (Internal.Id7 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
readonly get => (CullModeFlags)((Internal.Id6 >> 51) & 0x3);
set => Internal.Id6 = (Internal.Id6 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
}
public bool PrimitiveRestartEnable
{
readonly get => ((Internal.Id7 >> 53) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
readonly get => ((Internal.Id6 >> 53) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
}
public bool DepthClampEnable
{
readonly get => ((Internal.Id7 >> 54) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
readonly get => ((Internal.Id6 >> 54) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
}
public bool RasterizerDiscardEnable
{
readonly get => ((Internal.Id7 >> 55) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
readonly get => ((Internal.Id6 >> 55) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
}
public FrontFace FrontFace
{
readonly get => (FrontFace)((Internal.Id7 >> 56) & 0x1);
set => Internal.Id7 = (Internal.Id7 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
readonly get => (FrontFace)((Internal.Id6 >> 56) & 0x1);
set => Internal.Id6 = (Internal.Id6 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
}
public bool DepthBiasEnable
{
readonly get => ((Internal.Id7 >> 57) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
readonly get => ((Internal.Id6 >> 57) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
}
public bool DepthTestEnable
{
readonly get => ((Internal.Id7 >> 58) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
readonly get => ((Internal.Id6 >> 58) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
}
public bool DepthWriteEnable
{
readonly get => ((Internal.Id7 >> 59) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
readonly get => ((Internal.Id6 >> 59) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
}
public bool DepthBoundsTestEnable
{
readonly get => ((Internal.Id7 >> 60) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
readonly get => ((Internal.Id6 >> 60) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
}
public bool StencilTestEnable
{
readonly get => ((Internal.Id7 >> 61) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
readonly get => ((Internal.Id6 >> 61) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
}
public bool LogicOpEnable
{
readonly get => ((Internal.Id7 >> 62) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
readonly get => ((Internal.Id6 >> 62) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
}
public bool HasDepthStencil
{
readonly get => ((Internal.Id7 >> 63) & 0x1) != 0UL;
set => Internal.Id7 = (Internal.Id7 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
readonly get => ((Internal.Id6 >> 63) & 0x1) != 0UL;
set => Internal.Id6 = (Internal.Id6 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
}
public uint PatchControlPoints
{
readonly get => (uint)((Internal.Id8 >> 0) & 0xFFFFFFFF);
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
readonly get => (uint)((Internal.Id7 >> 0) & 0xFFFFFFFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
}
public uint SamplesCount
{
readonly get => (uint)((Internal.Id8 >> 32) & 0xFFFFFFFF);
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF) | ((ulong)value << 32);
readonly get => (uint)((Internal.Id7 >> 32) & 0xFFFFFFFF);
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF) | ((ulong)value << 32);
}
public bool AlphaToCoverageEnable
{
readonly get => ((Internal.Id9 >> 0) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
readonly get => ((Internal.Id8 >> 0) & 0x1) != 0UL;
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
}
public bool AlphaToOneEnable
{
readonly get => ((Internal.Id9 >> 1) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
readonly get => ((Internal.Id8 >> 1) & 0x1) != 0UL;
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
}
public bool AdvancedBlendSrcPreMultiplied
{
readonly get => ((Internal.Id9 >> 2) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
readonly get => ((Internal.Id8 >> 2) & 0x1) != 0UL;
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
}
public bool AdvancedBlendDstPreMultiplied
{
readonly get => ((Internal.Id9 >> 3) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
readonly get => ((Internal.Id8 >> 3) & 0x1) != 0UL;
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
}
public BlendOverlapEXT AdvancedBlendOverlap
{
readonly get => (BlendOverlapEXT)((Internal.Id9 >> 4) & 0x3);
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
readonly get => (BlendOverlapEXT)((Internal.Id8 >> 4) & 0x3);
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
}
public bool DepthMode
{
readonly get => ((Internal.Id9 >> 6) & 0x1) != 0UL;
set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
readonly get => ((Internal.Id8 >> 6) & 0x1) != 0UL;
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
}
public bool HasTessellationControlShader;
@ -408,8 +396,6 @@ namespace Ryujinx.Graphics.Vulkan
fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0])
fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0])
fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0])
fixed (Viewport* pViewports = &Internal.Viewports[0])
fixed (Rect2D* pScissors = &Internal.Scissors[0])
fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0])
{
var vertexInputState = new PipelineVertexInputStateCreateInfo
@ -472,18 +458,13 @@ namespace Ryujinx.Graphics.Vulkan
CullMode = CullMode,
FrontFace = FrontFace,
DepthBiasEnable = DepthBiasEnable,
DepthBiasClamp = DepthBiasClamp,
DepthBiasConstantFactor = DepthBiasConstantFactor,
DepthBiasSlopeFactor = DepthBiasSlopeFactor,
};
var viewportState = new PipelineViewportStateCreateInfo
{
SType = StructureType.PipelineViewportStateCreateInfo,
ViewportCount = ViewportsCount,
PViewports = pViewports,
ScissorCount = ScissorsCount,
PScissors = pScissors,
};
if (gd.Capabilities.SupportsDepthClipControl)
@ -511,19 +492,13 @@ namespace Ryujinx.Graphics.Vulkan
StencilFrontFailOp,
StencilFrontPassOp,
StencilFrontDepthFailOp,
StencilFrontCompareOp,
StencilFrontCompareMask,
StencilFrontWriteMask,
StencilFrontReference);
StencilFrontCompareOp);
var stencilBack = new StencilOpState(
StencilBackFailOp,
StencilBackPassOp,
StencilBackDepthFailOp,
StencilBackCompareOp,
StencilBackCompareMask,
StencilBackWriteMask,
StencilBackReference);
StencilBackCompareOp);
var depthStencilState = new PipelineDepthStencilStateCreateInfo
{
@ -531,12 +506,10 @@ namespace Ryujinx.Graphics.Vulkan
DepthTestEnable = DepthTestEnable,
DepthWriteEnable = DepthWriteEnable,
DepthCompareOp = DepthCompareOp,
DepthBoundsTestEnable = DepthBoundsTestEnable,
DepthBoundsTestEnable = false,
StencilTestEnable = StencilTestEnable,
Front = stencilFront,
Back = stencilBack,
MinDepthBounds = MinDepthBounds,
MaxDepthBounds = MaxDepthBounds,
};
uint blendEnables = 0;
@ -591,22 +564,21 @@ namespace Ryujinx.Graphics.Vulkan
}
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
dynamicStates[0] = DynamicState.Viewport;
dynamicStates[1] = DynamicState.Scissor;
dynamicStates[2] = DynamicState.DepthBias;
dynamicStates[3] = DynamicState.DepthBounds;
dynamicStates[4] = DynamicState.StencilCompareMask;
dynamicStates[5] = DynamicState.StencilWriteMask;
dynamicStates[6] = DynamicState.StencilReference;
dynamicStates[7] = DynamicState.BlendConstants;
dynamicStates[3] = DynamicState.StencilCompareMask;
dynamicStates[4] = DynamicState.StencilWriteMask;
dynamicStates[5] = DynamicState.StencilReference;
dynamicStates[6] = DynamicState.BlendConstants;
if (supportsExtDynamicState)
{
dynamicStates[8] = DynamicState.VertexInputBindingStrideExt;
dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
}
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
@ -632,7 +604,6 @@ namespace Ryujinx.Graphics.Vulkan
PDynamicState = &pipelineDynamicStateCreateInfo,
Layout = PipelineLayout,
RenderPass = renderPass,
BasePipelineIndex = -1,
};
Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle);

View File

@ -17,20 +17,17 @@ namespace Ryujinx.Graphics.Vulkan
public ulong Id4;
public ulong Id5;
public ulong Id6;
public ulong Id7;
public ulong Id8;
public ulong Id9;
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id6 >> 38) & 0xFF);
private readonly uint VertexBindingDescriptionsCount => (byte)((Id6 >> 46) & 0xFF);
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id7 >> 8) & 0xFF);
private readonly bool HasDepthStencil => ((Id7 >> 63) & 0x1) != 0UL;
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id5 >> 38) & 0xFF);
private readonly uint VertexBindingDescriptionsCount => (byte)((Id5 >> 46) & 0xFF);
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id6 >> 8) & 0xFF);
private readonly bool HasDepthStencil => ((Id6 >> 63) & 0x1) != 0UL;
public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions;
public Array33<VertexInputBindingDescription> VertexBindingDescriptions;
public Array16<Viewport> Viewports;
public Array16<Rect2D> Scissors;
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
public Array9<Format> AttachmentFormats;
public uint AttachmentIntegerFormatMask;
@ -45,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan
{
if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0)) ||
!Unsafe.As<ulong, Vector256<byte>>(ref Id4).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id4)) ||
!Unsafe.As<ulong, Vector128<byte>>(ref Id8).Equals(Unsafe.As<ulong, Vector128<byte>>(ref other.Id8)))
!Unsafe.As<ulong, Vector128<byte>>(ref Id7).Equals(Unsafe.As<ulong, Vector128<byte>>(ref other.Id7)))
{
return false;
}
@ -88,8 +85,7 @@ namespace Ryujinx.Graphics.Vulkan
Id5 * 23 ^
Id6 * 23 ^
Id7 * 23 ^
Id8 * 23 ^
Id9 * 23;
Id8 * 23;
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
{

View File

@ -233,7 +233,7 @@ namespace Ryujinx.UI.Windows
reader.ReadInt64(); // Padding
byte[] input = new byte[stream.Length - stream.Position];
stream.Read(input, 0, input.Length);
stream.ReadExactly(input, 0, input.Length);
long inputOffset = 0;

View File

@ -65,7 +65,7 @@ namespace Ryujinx.UI.App.Common
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
byte[] resourceByteArray = new byte[resourceStream.Length];
resourceStream.Read(resourceByteArray);
resourceStream.ReadExactly(resourceByteArray);
return resourceByteArray;
}

View File

@ -151,7 +151,7 @@ namespace Ryujinx.Ava.UI.ViewModels
reader.ReadInt64(); // Padding
byte[] input = new byte[stream.Length - stream.Position];
stream.Read(input, 0, input.Length);
stream.ReadExactly(input, 0, input.Length);
uint inputOffset = 0;