1
+ using System . Collections . Concurrent ;
2
+ using System . Diagnostics . CodeAnalysis ;
3
+ using System . Runtime . InteropServices ;
4
+ using Intersect . Client . Framework . Graphics ;
5
+ using Intersect . Core ;
6
+ using Intersect . Framework ;
7
+ using Intersect . Framework . Reflection ;
8
+ using Microsoft . Extensions . Logging ;
9
+ using Microsoft . Xna . Framework . Graphics ;
10
+ using BufferUsage = Intersect . Client . Framework . Graphics . BufferUsage ;
11
+ using PrimitiveType = Intersect . Client . Framework . Graphics . PrimitiveType ;
12
+
13
+ namespace Intersect . Client . MonoGame . Graphics ;
14
+
15
+ internal partial class MonoRenderer
16
+ {
17
+ private readonly ConcurrentDictionary < Microsoft . Xna . Framework . Graphics . IndexBuffer , IIndexBuffer > _allocatedIndexBuffers = [ ] ;
18
+ private long _allocatedIndexBuffersSize ;
19
+
20
+ private bool AddAllocatedIndexBuffer ( Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer , IIndexBuffer buffer )
21
+ {
22
+ if ( ! _allocatedIndexBuffers . TryAdd ( platformBuffer , buffer ) )
23
+ {
24
+ return false ;
25
+ }
26
+
27
+ MarkAllocated ( buffer ) ;
28
+
29
+ _allocatedIndexBuffersSize += MeasureDataSize ( platformBuffer ) ;
30
+ return true ;
31
+ }
32
+
33
+ private bool RemoveAllocatedIndexBuffer ( Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer , [ NotNullWhen ( true ) ] out IIndexBuffer ? buffer )
34
+ {
35
+ if ( ! _allocatedIndexBuffers . TryRemove ( platformBuffer , out buffer ) )
36
+ {
37
+ return false ;
38
+ }
39
+
40
+ _allocatedIndexBuffersSize -= MeasureDataSize ( platformBuffer ) ;
41
+ return true ;
42
+ }
43
+
44
+ private static long MeasureDataSize ( Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer )
45
+ {
46
+ return platformBuffer . IndexCount *
47
+ platformBuffer . IndexElementSize switch
48
+ {
49
+ IndexElementSize . SixteenBits => 2 ,
50
+ IndexElementSize . ThirtyTwoBits => 4 ,
51
+ _ => throw Exceptions . UnreachableInvalidEnum ( platformBuffer . IndexElementSize ) ,
52
+ } ;
53
+ }
54
+
55
+ public override IIndexBuffer CreateIndexBuffer < TIndex > ( int count , BufferUsage usage = BufferUsage . None , bool dynamic = false ) where TIndex : struct
56
+ {
57
+ Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer ;
58
+ var platformUsage = BufferUsageToMonoGameBufferUsage ( usage ) ;
59
+
60
+ if ( dynamic )
61
+ {
62
+ platformBuffer = new DynamicIndexBuffer ( _graphicsDevice , typeof ( TIndex ) , count , platformUsage ) ;
63
+ }
64
+ else
65
+ {
66
+ platformBuffer = new Microsoft . Xna . Framework . Graphics . IndexBuffer (
67
+ _graphicsDevice ,
68
+ typeof ( TIndex ) ,
69
+ count ,
70
+ platformUsage
71
+ ) ;
72
+ }
73
+
74
+ IndexBuffer buffer = new ( platformBuffer , typeof ( TIndex ) ) ;
75
+ platformBuffer . Disposing += IndexBufferOnDisposing ;
76
+ if ( AddAllocatedIndexBuffer ( platformBuffer , buffer ) )
77
+ {
78
+ return buffer ;
79
+ }
80
+
81
+ buffer . Dispose ( ) ;
82
+ throw new InvalidOperationException ( "Unable to track index buffer" ) ;
83
+ }
84
+
85
+ private void IndexBufferOnDisposing ( object ? sender , EventArgs args )
86
+ {
87
+ if ( sender is Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer )
88
+ {
89
+ OnPlatformIndexBufferDisposal ( platformBuffer ) ;
90
+ return ;
91
+ }
92
+
93
+ ApplicationContext . CurrentContext . Logger . LogError (
94
+ "Received disposal event but it was not from an instance of {ExpectedType} ({ActualType})" ,
95
+ typeof ( Microsoft . Xna . Framework . Graphics . IndexBuffer ) . GetName ( qualified : true ) ,
96
+ sender ? . GetType ( ) . GetName ( qualified : true ) ?? "null"
97
+ ) ;
98
+ }
99
+
100
+ private void OnPlatformIndexBufferDisposal ( Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer )
101
+ {
102
+ if ( RemoveAllocatedIndexBuffer ( platformBuffer , out var buffer ) )
103
+ {
104
+ MarkFreed ( buffer ) ;
105
+ }
106
+ else
107
+ {
108
+ ApplicationContext . CurrentContext . Logger . LogError (
109
+ "Failed to remove platform buffer from allocations, is it not tracked? '{BufferId}'" ,
110
+ platformBuffer . ToString ( )
111
+ ) ;
112
+ }
113
+ }
114
+
115
+ private sealed class IndexBuffer ( Microsoft . Xna . Framework . Graphics . IndexBuffer platformBuffer , Type indexType ) : GPUBuffer , IIndexBuffer
116
+ {
117
+ internal readonly Microsoft . Xna . Framework . Graphics . IndexBuffer PlatformBuffer = platformBuffer ;
118
+
119
+ public Type IndexType { get ; } = indexType ;
120
+
121
+ public override int Count => PlatformBuffer . IndexCount ;
122
+
123
+ public override int SizeBytes => ( int ) MeasureDataSize ( PlatformBuffer ) ;
124
+
125
+ protected override void ReleaseManagedResources ( )
126
+ {
127
+ base . ReleaseManagedResources ( ) ;
128
+
129
+ if ( ! PlatformBuffer . IsDisposed )
130
+ {
131
+ PlatformBuffer . Dispose ( ) ;
132
+ }
133
+ }
134
+
135
+ public bool GetData < TIndex > ( TIndex [ ] destination ) where TIndex : struct =>
136
+ GetData ( bufferOffset : 0 , destination : destination , destinationOffset : 0 , length : destination . Length ) ;
137
+
138
+ public bool GetData < TIndex > ( TIndex [ ] destination , int destinationOffset , int length ) where TIndex : struct =>
139
+ GetData ( bufferOffset : 0 , destination : destination , destinationOffset : destinationOffset , length : length ) ;
140
+
141
+ public bool GetData < TIndex > ( int bufferOffset , TIndex [ ] destination , int destinationOffset , int length )
142
+ where TIndex : struct
143
+ {
144
+ try
145
+ {
146
+ PlatformBuffer . GetData (
147
+ offsetInBytes : bufferOffset ,
148
+ data : destination ,
149
+ startIndex : destinationOffset ,
150
+ elementCount : length
151
+ ) ;
152
+ return true ;
153
+ }
154
+ catch ( Exception exception )
155
+ {
156
+ ApplicationContext . CurrentContext . Logger . LogError (
157
+ exception ,
158
+ "Failed to get data for {BufferType} {Id}" ,
159
+ nameof ( IIndexBuffer ) ,
160
+ Id
161
+ ) ;
162
+ return false ;
163
+ }
164
+ }
165
+
166
+ public bool SetData < TIndex > ( TIndex [ ] data ) where TIndex : struct => SetData (
167
+ destinationOffset : 0 ,
168
+ data : data ,
169
+ sourceOffset : 0 ,
170
+ length : data . Length ,
171
+ bufferWriteMode : BufferWriteMode . Overwrite
172
+ ) ;
173
+
174
+ public bool SetData < TIndex > ( TIndex [ ] data , int sourceOffset , int length )
175
+ where TIndex : struct => SetData (
176
+ destinationOffset : 0 ,
177
+ data : data ,
178
+ sourceOffset : sourceOffset ,
179
+ length : length ,
180
+ bufferWriteMode : BufferWriteMode . Overwrite
181
+ ) ;
182
+
183
+ public bool SetData < TIndex > ( int destinationOffset , TIndex [ ] data , int sourceOffset , int length )
184
+ where TIndex : struct => SetData (
185
+ destinationOffset : destinationOffset ,
186
+ data : data ,
187
+ sourceOffset : sourceOffset ,
188
+ length : length ,
189
+ bufferWriteMode : BufferWriteMode . Overwrite
190
+ ) ;
191
+
192
+ public bool SetData < TIndex > (
193
+ int destinationOffset ,
194
+ TIndex [ ] data ,
195
+ int sourceOffset ,
196
+ int length ,
197
+ BufferWriteMode bufferWriteMode
198
+ ) where TIndex : struct
199
+ {
200
+ if ( bufferWriteMode != BufferWriteMode . Overwrite )
201
+ {
202
+ if ( PlatformBuffer is not DynamicIndexBuffer dynamicBuffer )
203
+ {
204
+ ApplicationContext . CurrentContext . Logger . LogError (
205
+ "{BufferWriteMode} is only supported on dynamic buffers" ,
206
+ bufferWriteMode
207
+ ) ;
208
+ return false ;
209
+ }
210
+
211
+ SetDataOptions setDataOptions = bufferWriteMode switch
212
+ {
213
+ // ReSharper disable once UnreachableSwitchArmDueToIntegerAnalysis
214
+ BufferWriteMode . Overwrite => SetDataOptions . None ,
215
+ BufferWriteMode . Discard => SetDataOptions . Discard ,
216
+ BufferWriteMode . NoOverwrite => SetDataOptions . None ,
217
+ _ => throw Exceptions . UnreachableInvalidEnum ( value : bufferWriteMode ) ,
218
+ } ;
219
+ dynamicBuffer . SetData (
220
+ offsetInBytes : destinationOffset ,
221
+ data : data ,
222
+ startIndex : sourceOffset ,
223
+ elementCount : length ,
224
+ options : setDataOptions
225
+ ) ;
226
+ }
227
+ else
228
+ {
229
+ PlatformBuffer . SetData (
230
+ offsetInBytes : destinationOffset ,
231
+ data : data ,
232
+ startIndex : sourceOffset ,
233
+ elementCount : length
234
+ ) ;
235
+ }
236
+
237
+ return true ;
238
+ }
239
+ }
240
+ }
0 commit comments