aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/IndexBufferState.cs
blob: d26fea307ee17502caf5185c8b114e1ead2d33cd (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
using Ryujinx.Graphics.GAL;
using IndexType = Silk.NET.Vulkan.IndexType;

namespace Ryujinx.Graphics.Vulkan
{
    internal struct IndexBufferState
    {
        private const int IndexBufferMaxMirrorable = 0x20000;

        public static IndexBufferState Null => new(BufferHandle.Null, 0, 0);

        private readonly int _offset;
        private readonly int _size;
        private readonly IndexType _type;

        private readonly BufferHandle _handle;
        private Auto<DisposableBuffer> _buffer;

        public IndexBufferState(BufferHandle handle, int offset, int size, IndexType type)
        {
            _handle = handle;
            _offset = offset;
            _size = size;
            _type = type;
            _buffer = null;
        }

        public IndexBufferState(BufferHandle handle, int offset, int size)
        {
            _handle = handle;
            _offset = offset;
            _size = size;
            _type = IndexType.Uint16;
            _buffer = null;
        }

        public void BindIndexBuffer(VulkanRenderer gd, CommandBufferScoped cbs)
        {
            Auto<DisposableBuffer> autoBuffer;
            int offset, size;
            IndexType type = _type;
            bool mirrorable = false;

            if (_type == IndexType.Uint8Ext && !gd.Capabilities.SupportsIndexTypeUint8)
            {
                // Index type is not supported. Convert to I16.
                autoBuffer = gd.BufferManager.GetBufferI8ToI16(cbs, _handle, _offset, _size);

                type = IndexType.Uint16;
                offset = 0;
                size = _size * 2;
            }
            else
            {
                autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int bufferSize);

                if (_offset >= bufferSize)
                {
                    autoBuffer = null;
                }

                mirrorable = _size < IndexBufferMaxMirrorable;

                offset = _offset;
                size = _size;
            }

            _buffer = autoBuffer;

            if (autoBuffer != null)
            {
                DisposableBuffer buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, size, out _) : autoBuffer.Get(cbs, offset, size);

                gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, buffer.Value, (ulong)offset, type);
            }
        }

        public void BindConvertedIndexBuffer(
            VulkanRenderer gd,
            CommandBufferScoped cbs,
            int firstIndex,
            int indexCount,
            int convertedCount,
            IndexBufferPattern pattern)
        {
            Auto<DisposableBuffer> autoBuffer;

            // Convert the index buffer using the given pattern.
            int indexSize = GetIndexSize();

            int firstIndexOffset = firstIndex * indexSize;

            autoBuffer = gd.BufferManager.GetBufferTopologyConversion(cbs, _handle, _offset + firstIndexOffset, indexCount * indexSize, pattern, indexSize);

            int size = convertedCount * 4;

            _buffer = autoBuffer;

            if (autoBuffer != null)
            {
                gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, autoBuffer.Get(cbs, 0, size).Value, 0, IndexType.Uint32);
            }
        }

        public Auto<DisposableBuffer> BindConvertedIndexBufferIndirect(
            VulkanRenderer gd,
            CommandBufferScoped cbs,
            BufferRange indirectBuffer,
            BufferRange drawCountBuffer,
            IndexBufferPattern pattern,
            bool hasDrawCount,
            int maxDrawCount,
            int indirectDataStride)
        {
            // Convert the index buffer using the given pattern.
            int indexSize = GetIndexSize();

            (var indexBufferAuto, var indirectBufferAuto) = gd.BufferManager.GetBufferTopologyConversionIndirect(
                gd,
                cbs,
                new BufferRange(_handle, _offset, _size),
                indirectBuffer,
                drawCountBuffer,
                pattern,
                indexSize,
                hasDrawCount,
                maxDrawCount,
                indirectDataStride);

            int convertedCount = pattern.GetConvertedCount(_size / indexSize);
            int size = convertedCount * 4;

            _buffer = indexBufferAuto;

            if (indexBufferAuto != null)
            {
                gd.Api.CmdBindIndexBuffer(cbs.CommandBuffer, indexBufferAuto.Get(cbs, 0, size).Value, 0, IndexType.Uint32);
            }

            return indirectBufferAuto;
        }

        private readonly int GetIndexSize()
        {
            return _type switch
            {
                IndexType.Uint32 => 4,
                IndexType.Uint16 => 2,
                _ => 1,
            };
        }

        public readonly bool BoundEquals(Auto<DisposableBuffer> buffer)
        {
            return _buffer == buffer;
        }

        public void Swap(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
        {
            if (_buffer == from)
            {
                _buffer = to;
            }
        }

        public readonly bool Overlaps(Auto<DisposableBuffer> buffer, int offset, int size)
        {
            return buffer == _buffer && offset < _offset + _size && offset + size > _offset;
        }
    }
}