using Ryujinx.Common.Memory; using Silk.NET.Vulkan; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; namespace Ryujinx.Graphics.Vulkan { struct PipelineUid : IRefEquatable { public ulong Id0; public ulong Id1; public ulong Id2; public ulong Id3; 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; public Array32 VertexAttributeDescriptions; public Array33 VertexBindingDescriptions; public Array16 Viewports; public Array16 Scissors; public Array8 ColorBlendAttachmentState; public Array9 AttachmentFormats; public uint AttachmentIntegerFormatMask; public bool LogicOpsAllowed; public readonly override bool Equals(object obj) { return obj is PipelineUid other && Equals(other); } public bool Equals(ref PipelineUid other) { if (!Unsafe.As>(ref Id0).Equals(Unsafe.As>(ref other.Id0)) || !Unsafe.As>(ref Id4).Equals(Unsafe.As>(ref other.Id4)) || !Unsafe.As>(ref Id8).Equals(Unsafe.As>(ref other.Id8))) { return false; } if (!SequenceEqual(VertexAttributeDescriptions.AsSpan(), other.VertexAttributeDescriptions.AsSpan(), VertexAttributeDescriptionsCount)) { return false; } if (!SequenceEqual(VertexBindingDescriptions.AsSpan(), other.VertexBindingDescriptions.AsSpan(), VertexBindingDescriptionsCount)) { return false; } if (!SequenceEqual(ColorBlendAttachmentState.AsSpan(), other.ColorBlendAttachmentState.AsSpan(), ColorBlendAttachmentStateCount)) { return false; } if (!SequenceEqual(AttachmentFormats.AsSpan(), other.AttachmentFormats.AsSpan(), ColorBlendAttachmentStateCount + (HasDepthStencil ? 1u : 0u))) { return false; } return true; } private static bool SequenceEqual(ReadOnlySpan x, ReadOnlySpan y, uint count) where T : unmanaged { return MemoryMarshal.Cast(x[..(int)count]).SequenceEqual(MemoryMarshal.Cast(y[..(int)count])); } public override int GetHashCode() { ulong hash64 = Id0 * 23 ^ Id1 * 23 ^ Id2 * 23 ^ Id3 * 23 ^ Id4 * 23 ^ Id5 * 23 ^ Id6 * 23 ^ Id7 * 23 ^ Id8 * 23 ^ Id9 * 23; for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++) { hash64 ^= VertexAttributeDescriptions[i].Binding * 23; hash64 ^= (uint)VertexAttributeDescriptions[i].Format * 23; hash64 ^= VertexAttributeDescriptions[i].Location * 23; hash64 ^= VertexAttributeDescriptions[i].Offset * 23; } for (int i = 0; i < (int)VertexBindingDescriptionsCount; i++) { hash64 ^= VertexBindingDescriptions[i].Binding * 23; hash64 ^= (uint)VertexBindingDescriptions[i].InputRate * 23; hash64 ^= VertexBindingDescriptions[i].Stride * 23; } for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++) { hash64 ^= ColorBlendAttachmentState[i].BlendEnable * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].SrcColorBlendFactor * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].DstColorBlendFactor * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].ColorBlendOp * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].SrcAlphaBlendFactor * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].DstAlphaBlendFactor * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].AlphaBlendOp * 23; hash64 ^= (uint)ColorBlendAttachmentState[i].ColorWriteMask * 23; } for (int i = 0; i < (int)ColorBlendAttachmentStateCount; i++) { hash64 ^= (uint)AttachmentFormats[i] * 23; } return (int)hash64 ^ ((int)(hash64 >> 32) * 17); } } }