aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/PipelineUid.cs
blob: 238f06e2ac5d44bd17f4d069acbc7b985fa7968b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
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<PipelineUid>
    {
        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<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;
        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<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)))
            {
                return false;
            }

            if (!SequenceEqual<VertexInputAttributeDescription>(VertexAttributeDescriptions.AsSpan(), other.VertexAttributeDescriptions.AsSpan(), VertexAttributeDescriptionsCount))
            {
                return false;
            }

            if (!SequenceEqual<VertexInputBindingDescription>(VertexBindingDescriptions.AsSpan(), other.VertexBindingDescriptions.AsSpan(), VertexBindingDescriptionsCount))
            {
                return false;
            }

            if (!SequenceEqual<PipelineColorBlendAttachmentState>(ColorBlendAttachmentState.AsSpan(), other.ColorBlendAttachmentState.AsSpan(), ColorBlendAttachmentStateCount))
            {
                return false;
            }

            if (!SequenceEqual<Format>(AttachmentFormats.AsSpan(), other.AttachmentFormats.AsSpan(), ColorBlendAttachmentStateCount + (HasDepthStencil ? 1u : 0u)))
            {
                return false;
            }

            return true;
        }

        private static bool SequenceEqual<T>(ReadOnlySpan<T> x, ReadOnlySpan<T> y, uint count) where T : unmanaged
        {
            return MemoryMarshal.Cast<T, byte>(x[..(int)count]).SequenceEqual(MemoryMarshal.Cast<T, byte>(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);
        }
    }
}