aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/SpecInfo.cs
blob: ecb2abfc6a26c5ce0cab4194e3ef93a2d0a51e9e (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
using Silk.NET.Vulkan;
using System;

namespace Ryujinx.Graphics.Vulkan
{
    public enum SpecConstType
    {
        Bool32,
        Int16,
        Int32,
        Int64,
        Float16,
        Float32,
        Float64,
    }

    sealed class SpecDescription
    {
        public readonly SpecializationInfo Info;
        public readonly SpecializationMapEntry[] Map;

        // For mapping a simple packed struct or single entry
        public SpecDescription(params (uint Id, SpecConstType Type)[] description)
        {
            int count = description.Length;
            Map = new SpecializationMapEntry[count];

            uint structSize = 0;

            for (int i = 0; i < Map.Length; ++i)
            {
                var typeSize = SizeOf(description[i].Type);
                Map[i] = new SpecializationMapEntry(description[i].Id, structSize, typeSize);
                structSize += typeSize;
            }

            Info = new SpecializationInfo
            {
                DataSize = structSize,
                MapEntryCount = (uint)count,
            };
        }

        // For advanced mapping with overlapping or staggered fields
        public SpecDescription(SpecializationMapEntry[] map)
        {
            Map = map;

            uint structSize = 0;
            for (int i = 0; i < map.Length; ++i)
            {
                structSize = Math.Max(structSize, map[i].Offset + (uint)map[i].Size);
            }

            Info = new SpecializationInfo
            {
                DataSize = structSize,
                MapEntryCount = (uint)map.Length,
            };
        }

        private static uint SizeOf(SpecConstType type) => type switch
        {
            SpecConstType.Int16 or SpecConstType.Float16 => 2,
            SpecConstType.Bool32 or SpecConstType.Int32 or SpecConstType.Float32 => 4,
            SpecConstType.Int64 or SpecConstType.Float64 => 8,
            _ => throw new ArgumentOutOfRangeException(nameof(type)),
        };

        private SpecDescription()
        {
            Info = new();
        }

        public static readonly SpecDescription Empty = new();
    }

    readonly struct SpecData : IRefEquatable<SpecData>
    {
        private readonly byte[] _data;
        private readonly int _hash;

        public int Length => _data.Length;
        public ReadOnlySpan<byte> Span => _data.AsSpan();
        public override int GetHashCode() => _hash;

        public SpecData(ReadOnlySpan<byte> data)
        {
            _data = new byte[data.Length];
            data.CopyTo(_data);

            var hc = new HashCode();
            hc.AddBytes(data);
            _hash = hc.ToHashCode();
        }

        public override bool Equals(object obj) => obj is SpecData other && Equals(other);
        public bool Equals(ref SpecData other) => _data.AsSpan().SequenceEqual(other._data);
    }
}