/ src / Ryujinx.Graphics.Gpu / Engine / Threed / ThreedClass.cs
ThreedClass.cs
  1  using Ryujinx.Common.Memory;
  2  using Ryujinx.Graphics.Device;
  3  using Ryujinx.Graphics.GAL;
  4  using Ryujinx.Graphics.Gpu.Engine.GPFifo;
  5  using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
  6  using Ryujinx.Graphics.Gpu.Engine.Threed.Blender;
  7  using Ryujinx.Graphics.Gpu.Engine.Types;
  8  using Ryujinx.Graphics.Gpu.Synchronization;
  9  using Ryujinx.Memory.Range;
 10  using System;
 11  using System.Collections.Generic;
 12  using System.Runtime.CompilerServices;
 13  using System.Runtime.Intrinsics;
 14  
 15  namespace Ryujinx.Graphics.Gpu.Engine.Threed
 16  {
 17      /// <summary>
 18      /// Represents a 3D engine class.
 19      /// </summary>
 20      class ThreedClass : IDeviceState, IDisposable
 21      {
 22          private readonly GpuContext _context;
 23          private readonly GPFifoClass _fifoClass;
 24          private readonly DeviceStateWithShadow<ThreedClassState> _state;
 25  
 26          private readonly InlineToMemoryClass _i2mClass;
 27          private readonly AdvancedBlendManager _blendManager;
 28          private readonly DrawManager _drawManager;
 29          private readonly SemaphoreUpdater _semaphoreUpdater;
 30          private readonly ConstantBufferUpdater _cbUpdater;
 31          private readonly StateUpdater _stateUpdater;
 32  
 33          private SetMmeShadowRamControlMode ShadowMode => _state.State.SetMmeShadowRamControlMode;
 34  
 35          /// <summary>
 36          /// Creates a new instance of the 3D engine class.
 37          /// </summary>
 38          /// <param name="context">GPU context</param>
 39          /// <param name="channel">GPU channel</param>
 40          public ThreedClass(GpuContext context, GpuChannel channel, GPFifoClass fifoClass)
 41          {
 42              _context = context;
 43              _fifoClass = fifoClass;
 44              _state = new DeviceStateWithShadow<ThreedClassState>(new Dictionary<string, RwCallback>
 45              {
 46                  { nameof(ThreedClassState.LaunchDma), new RwCallback(LaunchDma, null) },
 47                  { nameof(ThreedClassState.LoadInlineData), new RwCallback(LoadInlineData, null) },
 48                  { nameof(ThreedClassState.SyncpointAction), new RwCallback(IncrementSyncpoint, null) },
 49                  { nameof(ThreedClassState.InvalidateSamplerCacheNoWfi), new RwCallback(InvalidateSamplerCacheNoWfi, null) },
 50                  { nameof(ThreedClassState.InvalidateTextureHeaderCacheNoWfi), new RwCallback(InvalidateTextureHeaderCacheNoWfi, null) },
 51                  { nameof(ThreedClassState.TextureBarrier), new RwCallback(TextureBarrier, null) },
 52                  { nameof(ThreedClassState.LoadBlendUcodeStart), new RwCallback(LoadBlendUcodeStart, null) },
 53                  { nameof(ThreedClassState.LoadBlendUcodeInstruction), new RwCallback(LoadBlendUcodeInstruction, null) },
 54                  { nameof(ThreedClassState.TextureBarrierTiled), new RwCallback(TextureBarrierTiled, null) },
 55                  { nameof(ThreedClassState.DrawTextureSrcY), new RwCallback(DrawTexture, null) },
 56                  { nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceFirst), new RwCallback(DrawVertexArrayBeginEndInstanceFirst, null) },
 57                  { nameof(ThreedClassState.DrawVertexArrayBeginEndInstanceSubsequent), new RwCallback(DrawVertexArrayBeginEndInstanceSubsequent, null) },
 58                  { nameof(ThreedClassState.VbElementU8), new RwCallback(VbElementU8, null) },
 59                  { nameof(ThreedClassState.VbElementU16), new RwCallback(VbElementU16, null) },
 60                  { nameof(ThreedClassState.VbElementU32), new RwCallback(VbElementU32, null) },
 61                  { nameof(ThreedClassState.ResetCounter), new RwCallback(ResetCounter, null) },
 62                  { nameof(ThreedClassState.RenderEnableCondition), new RwCallback(null, Zero) },
 63                  { nameof(ThreedClassState.DrawEnd), new RwCallback(DrawEnd, null) },
 64                  { nameof(ThreedClassState.DrawBegin), new RwCallback(DrawBegin, null) },
 65                  { nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer32BeginEndInstanceFirst, null) },
 66                  { nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer16BeginEndInstanceFirst, null) },
 67                  { nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceFirst), new RwCallback(DrawIndexBuffer8BeginEndInstanceFirst, null) },
 68                  { nameof(ThreedClassState.DrawIndexBuffer32BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer32BeginEndInstanceSubsequent, null) },
 69                  { nameof(ThreedClassState.DrawIndexBuffer16BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer16BeginEndInstanceSubsequent, null) },
 70                  { nameof(ThreedClassState.DrawIndexBuffer8BeginEndInstanceSubsequent), new RwCallback(DrawIndexBuffer8BeginEndInstanceSubsequent, null) },
 71                  { nameof(ThreedClassState.IndexBufferCount), new RwCallback(SetIndexBufferCount, null) },
 72                  { nameof(ThreedClassState.Clear), new RwCallback(Clear, null) },
 73                  { nameof(ThreedClassState.SemaphoreControl), new RwCallback(Report, null) },
 74                  { nameof(ThreedClassState.SetFalcon04), new RwCallback(SetFalcon04, null) },
 75                  { nameof(ThreedClassState.UniformBufferUpdateData), new RwCallback(ConstantBufferUpdate, null) },
 76                  { nameof(ThreedClassState.UniformBufferBindVertex), new RwCallback(ConstantBufferBindVertex, null) },
 77                  { nameof(ThreedClassState.UniformBufferBindTessControl), new RwCallback(ConstantBufferBindTessControl, null) },
 78                  { nameof(ThreedClassState.UniformBufferBindTessEvaluation), new RwCallback(ConstantBufferBindTessEvaluation, null) },
 79                  { nameof(ThreedClassState.UniformBufferBindGeometry), new RwCallback(ConstantBufferBindGeometry, null) },
 80                  { nameof(ThreedClassState.UniformBufferBindFragment), new RwCallback(ConstantBufferBindFragment, null) },
 81              });
 82  
 83              _i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
 84  
 85              var spec = new SpecializationStateUpdater(context);
 86              var drawState = new DrawState();
 87  
 88              _drawManager = new DrawManager(context, channel, _state, drawState, spec);
 89              _blendManager = new AdvancedBlendManager(_state);
 90              _semaphoreUpdater = new SemaphoreUpdater(context, channel, _state);
 91              _cbUpdater = new ConstantBufferUpdater(channel, _state);
 92              _stateUpdater = new StateUpdater(context, channel, _state, drawState, _blendManager, spec);
 93  
 94              // This defaults to "always", even without any register write.
 95              // Reads just return 0, regardless of what was set there.
 96              _state.State.RenderEnableCondition = Condition.Always;
 97          }
 98  
 99          /// <summary>
100          /// Reads data from the class registers.
101          /// </summary>
102          /// <param name="offset">Register byte offset</param>
103          /// <returns>Data at the specified offset</returns>
104          [MethodImpl(MethodImplOptions.AggressiveInlining)]
105          public int Read(int offset) => _state.Read(offset);
106  
107          /// <summary>
108          /// Writes data to the class registers.
109          /// </summary>
110          /// <param name="offset">Register byte offset</param>
111          /// <param name="data">Data to be written</param>
112          [MethodImpl(MethodImplOptions.AggressiveInlining)]
113          public void Write(int offset, int data)
114          {
115              _state.WriteWithRedundancyCheck(offset, data, out bool valueChanged);
116  
117              if (valueChanged)
118              {
119                  _stateUpdater.SetDirty(offset);
120              }
121          }
122  
123          /// <summary>
124          /// Sets the shadow ram control value of all sub-channels.
125          /// </summary>
126          /// <param name="control">New shadow ram control value</param>
127          public void SetShadowRamControl(int control)
128          {
129              _state.State.SetMmeShadowRamControl = (uint)control;
130          }
131  
132          /// <summary>
133          /// Updates current host state for all registers modified since the last call to this method.
134          /// </summary>
135          public void UpdateState()
136          {
137              _fifoClass.CreatePendingSyncs();
138              _cbUpdater.FlushUboDirty();
139              _stateUpdater.Update();
140          }
141  
142          /// <summary>
143          /// Updates current host state for all registers modified since the last call to this method.
144          /// </summary>
145          /// <param name="mask">Mask where each bit set indicates that the respective state group index should be checked</param>
146          public void UpdateState(ulong mask)
147          {
148              _stateUpdater.Update(mask);
149          }
150  
151          /// <summary>
152          /// Updates render targets (color and depth-stencil buffers) based on current render target state.
153          /// </summary>
154          /// <param name="updateFlags">Flags indicating which render targets should be updated and how</param>
155          /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
156          public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
157          {
158              _stateUpdater.UpdateRenderTargetState(updateFlags, singleUse);
159          }
160  
161          /// <summary>
162          /// Updates scissor based on current render target state.
163          /// </summary>
164          public void UpdateScissorState()
165          {
166              _stateUpdater.UpdateScissorState();
167          }
168  
169          /// <summary>
170          /// Marks the entire state as dirty, forcing a full host state update before the next draw.
171          /// </summary>
172          public void ForceStateDirty()
173          {
174              _drawManager.ForceStateDirty();
175              _stateUpdater.SetAllDirty();
176          }
177  
178          /// <summary>
179          /// Marks the specified register offset as dirty, forcing the associated state to update on the next draw.
180          /// </summary>
181          /// <param name="offset">Register offset</param>
182          public void ForceStateDirty(int offset)
183          {
184              _stateUpdater.SetDirty(offset);
185          }
186  
187          /// <summary>
188          /// Marks the specified register range for a group index as dirty, forcing the associated state to update on the next draw.
189          /// </summary>
190          /// <param name="groupIndex">Index of the group to dirty</param>
191          public void ForceStateDirtyByIndex(int groupIndex)
192          {
193              _stateUpdater.ForceDirty(groupIndex);
194          }
195  
196          /// <summary>
197          /// Forces the shaders to be rebound on the next draw.
198          /// </summary>
199          public void ForceShaderUpdate()
200          {
201              _stateUpdater.ForceShaderUpdate();
202          }
203  
204          /// <summary>
205          /// Create any syncs from WaitForIdle command that are currently pending.
206          /// </summary>
207          public void CreatePendingSyncs()
208          {
209              _fifoClass.CreatePendingSyncs();
210          }
211  
212          /// <summary>
213          /// Flushes any queued UBO updates.
214          /// </summary>
215          public void FlushUboDirty()
216          {
217              _cbUpdater.FlushUboDirty();
218          }
219  
220          /// <summary>
221          /// Perform any deferred draws.
222          /// </summary>
223          public void PerformDeferredDraws()
224          {
225              _drawManager.PerformDeferredDraws(this);
226          }
227  
228          /// <summary>
229          /// Updates the currently bound constant buffer.
230          /// </summary>
231          /// <param name="data">Data to be written to the buffer</param>
232          public void ConstantBufferUpdate(ReadOnlySpan<int> data)
233          {
234              _cbUpdater.Update(data);
235          }
236  
237          /// <summary>
238          /// Test if two 32 byte structs are equal. 
239          /// </summary>
240          /// <typeparam name="T">Type of the 32-byte struct</typeparam>
241          /// <param name="lhs">First struct</param>
242          /// <param name="rhs">Second struct</param>
243          /// <returns>True if equal, false otherwise</returns>
244          [MethodImpl(MethodImplOptions.AggressiveInlining)]
245          private static bool UnsafeEquals32Byte<T>(ref T lhs, ref T rhs) where T : unmanaged
246          {
247              if (Vector256.IsHardwareAccelerated)
248              {
249                  return Vector256.EqualsAll(
250                      Unsafe.As<T, Vector256<uint>>(ref lhs),
251                      Unsafe.As<T, Vector256<uint>>(ref rhs)
252                  );
253              }
254              else
255              {
256                  ref var lhsVec = ref Unsafe.As<T, Vector128<uint>>(ref lhs);
257                  ref var rhsVec = ref Unsafe.As<T, Vector128<uint>>(ref rhs);
258  
259                  return Vector128.EqualsAll(lhsVec, rhsVec) &&
260                      Vector128.EqualsAll(Unsafe.Add(ref lhsVec, 1), Unsafe.Add(ref rhsVec, 1));
261              }
262          }
263  
264          /// <summary>
265          /// Updates blend enable. Respects current shadow mode.
266          /// </summary>
267          /// <param name="masks">Blend enable</param>
268          public void UpdateBlendEnable(ref Array8<Boolean32> enable)
269          {
270              var shadow = ShadowMode;
271              ref var state = ref _state.State.BlendEnable;
272  
273              if (shadow.IsReplay())
274              {
275                  enable = _state.ShadowState.BlendEnable;
276              }
277  
278              if (!UnsafeEquals32Byte(ref enable, ref state))
279              {
280                  state = enable;
281  
282                  _stateUpdater.ForceDirty(StateUpdater.BlendStateIndex);
283              }
284  
285              if (shadow.IsTrack())
286              {
287                  _state.ShadowState.BlendEnable = enable;
288              }
289          }
290  
291          /// <summary>
292          /// Updates color masks. Respects current shadow mode.
293          /// </summary>
294          /// <param name="masks">Color masks</param>
295          public void UpdateColorMasks(ref Array8<RtColorMask> masks)
296          {
297              var shadow = ShadowMode;
298              ref var state = ref _state.State.RtColorMask;
299  
300              if (shadow.IsReplay())
301              {
302                  masks = _state.ShadowState.RtColorMask;
303              }
304  
305              if (!UnsafeEquals32Byte(ref masks, ref state))
306              {
307                  state = masks;
308  
309                  _stateUpdater.ForceDirty(StateUpdater.RtColorMaskIndex);
310              }
311  
312              if (shadow.IsTrack())
313              {
314                  _state.ShadowState.RtColorMask = masks;
315              }
316          }
317  
318          /// <summary>
319          /// Updates index buffer state for an indexed draw. Respects current shadow mode.
320          /// </summary>
321          /// <param name="addrHigh">High part of the address</param>
322          /// <param name="addrLow">Low part of the address</param>
323          /// <param name="type">Type of the binding</param>
324          public void UpdateIndexBuffer(uint addrHigh, uint addrLow, IndexType type)
325          {
326              var shadow = ShadowMode;
327              ref var state = ref _state.State.IndexBufferState;
328  
329              if (shadow.IsReplay())
330              {
331                  ref var shadowState = ref _state.ShadowState.IndexBufferState;
332                  addrHigh = shadowState.Address.High;
333                  addrLow = shadowState.Address.Low;
334                  type = shadowState.Type;
335              }
336  
337              if (state.Address.High != addrHigh || state.Address.Low != addrLow || state.Type != type)
338              {
339                  state.Address.High = addrHigh;
340                  state.Address.Low = addrLow;
341                  state.Type = type;
342  
343                  _stateUpdater.ForceDirty(StateUpdater.IndexBufferStateIndex);
344              }
345  
346              if (shadow.IsTrack())
347              {
348                  ref var shadowState = ref _state.ShadowState.IndexBufferState;
349                  shadowState.Address.High = addrHigh;
350                  shadowState.Address.Low = addrLow;
351                  shadowState.Type = type;
352              }
353          }
354  
355          /// <summary>
356          /// Updates uniform buffer state for update or bind. Respects current shadow mode.
357          /// </summary>
358          /// <param name="size">Size of the binding</param>
359          /// <param name="addrHigh">High part of the addrsss</param>
360          /// <param name="addrLow">Low part of the address</param>
361          public void UpdateUniformBufferState(int size, uint addrHigh, uint addrLow)
362          {
363              var shadow = ShadowMode;
364              ref var state = ref _state.State.UniformBufferState;
365  
366              if (shadow.IsReplay())
367              {
368                  ref var shadowState = ref _state.ShadowState.UniformBufferState;
369                  size = shadowState.Size;
370                  addrHigh = shadowState.Address.High;
371                  addrLow = shadowState.Address.Low;
372              }
373  
374              state.Size = size;
375              state.Address.High = addrHigh;
376              state.Address.Low = addrLow;
377  
378              if (shadow.IsTrack())
379              {
380                  ref var shadowState = ref _state.ShadowState.UniformBufferState;
381                  shadowState.Size = size;
382                  shadowState.Address.High = addrHigh;
383                  shadowState.Address.Low = addrLow;
384              }
385          }
386  
387          /// <summary>
388          /// Updates a shader offset. Respects current shadow mode.
389          /// </summary>
390          /// <param name="index">Index of the shader to update</param>
391          /// <param name="offset">Offset to update with</param>
392          public void SetShaderOffset(int index, uint offset)
393          {
394              var shadow = ShadowMode;
395              ref var shaderState = ref _state.State.ShaderState[index];
396  
397              if (shadow.IsReplay())
398              {
399                  offset = _state.ShadowState.ShaderState[index].Offset;
400              }
401  
402              if (shaderState.Offset != offset)
403              {
404                  shaderState.Offset = offset;
405  
406                  _stateUpdater.ForceDirty(StateUpdater.ShaderStateIndex);
407              }
408  
409              if (shadow.IsTrack())
410              {
411                  _state.ShadowState.ShaderState[index].Offset = offset;
412              }
413          }
414  
415          /// <summary>
416          /// Updates uniform buffer state for update. Respects current shadow mode.
417          /// </summary>
418          /// <param name="ubState">Uniform buffer state</param>
419          public void UpdateUniformBufferState(UniformBufferState ubState)
420          {
421              var shadow = ShadowMode;
422              ref var state = ref _state.State.UniformBufferState;
423  
424              if (shadow.IsReplay())
425              {
426                  ubState = _state.ShadowState.UniformBufferState;
427              }
428  
429              state = ubState;
430  
431              if (shadow.IsTrack())
432              {
433                  _state.ShadowState.UniformBufferState = ubState;
434              }
435          }
436  
437          /// <summary>
438          /// Launches the Inline-to-Memory DMA copy operation.
439          /// </summary>
440          /// <param name="argument">Method call argument</param>
441          private void LaunchDma(int argument)
442          {
443              _i2mClass.LaunchDma(ref Unsafe.As<ThreedClassState, InlineToMemoryClassState>(ref _state.State), argument);
444          }
445  
446          /// <summary>
447          /// Pushes a block of data to the Inline-to-Memory engine.
448          /// </summary>
449          /// <param name="data">Data to push</param>
450          public void LoadInlineData(ReadOnlySpan<int> data)
451          {
452              _i2mClass.LoadInlineData(data);
453          }
454  
455          /// <summary>
456          /// Pushes a word of data to the Inline-to-Memory engine.
457          /// </summary>
458          /// <param name="argument">Method call argument</param>
459          private void LoadInlineData(int argument)
460          {
461              _i2mClass.LoadInlineData(argument);
462          }
463  
464          /// <summary>
465          /// Performs an incrementation on a syncpoint.
466          /// </summary>
467          /// <param name="argument">Method call argument</param>
468          public void IncrementSyncpoint(int argument)
469          {
470              uint syncpointId = (uint)argument & 0xFFFF;
471  
472              _context.AdvanceSequence();
473              _context.CreateHostSyncIfNeeded(HostSyncFlags.StrictSyncpoint);
474              _context.Renderer.UpdateCounters(); // Poll the query counters, the game may want an updated result.
475              _context.Synchronization.IncrementSyncpoint(syncpointId);
476          }
477  
478          /// <summary>
479          /// Invalidates the cache with the sampler descriptors from the sampler pool.
480          /// </summary>
481          /// <param name="argument">Method call argument (unused)</param>
482          private void InvalidateSamplerCacheNoWfi(int argument)
483          {
484              _context.AdvanceSequence();
485          }
486  
487          /// <summary>
488          /// Invalidates the cache with the texture descriptors from the texture pool.
489          /// </summary>
490          /// <param name="argument">Method call argument (unused)</param>
491          private void InvalidateTextureHeaderCacheNoWfi(int argument)
492          {
493              _context.AdvanceSequence();
494          }
495  
496          /// <summary>
497          /// Issues a texture barrier.
498          /// This waits until previous texture writes from the GPU to finish, before
499          /// performing new operations with said textures.
500          /// </summary>
501          /// <param name="argument">Method call argument (unused)</param>
502          private void TextureBarrier(int argument)
503          {
504              _context.Renderer.Pipeline.TextureBarrier();
505          }
506  
507          /// <summary>
508          /// Sets the start offset of the blend microcode in memory.
509          /// </summary>
510          /// <param name="argument">Method call argument</param>
511          private void LoadBlendUcodeStart(int argument)
512          {
513              _blendManager.LoadBlendUcodeStart(argument);
514          }
515  
516          /// <summary>
517          /// Pushes one word of blend microcode.
518          /// </summary>
519          /// <param name="argument">Method call argument</param>
520          private void LoadBlendUcodeInstruction(int argument)
521          {
522              _blendManager.LoadBlendUcodeInstruction(argument);
523          }
524  
525          /// <summary>
526          /// Issues a texture barrier.
527          /// This waits until previous texture writes from the GPU to finish, before
528          /// performing new operations with said textures.
529          /// This performs a per-tile wait, it is only valid if both the previous write
530          /// and current access has the same access patterns.
531          /// This may be faster than the regular barrier on tile-based rasterizers.
532          /// </summary>
533          /// <param name="argument">Method call argument (unused)</param>
534          private void TextureBarrierTiled(int argument)
535          {
536              _context.Renderer.Pipeline.TextureBarrierTiled();
537          }
538  
539          /// <summary>
540          /// Draws a texture, without needing to specify shader programs.
541          /// </summary>
542          /// <param name="argument">Method call argument</param>
543          private void DrawTexture(int argument)
544          {
545              _drawManager.DrawTexture(this, argument);
546          }
547  
548          /// <summary>
549          /// Performs a non-indexed draw with the specified topology, index and count.
550          /// </summary>
551          /// <param name="argument">Method call argument</param>
552          private void DrawVertexArrayBeginEndInstanceFirst(int argument)
553          {
554              _drawManager.DrawVertexArrayBeginEndInstanceFirst(this, argument);
555          }
556  
557          /// <summary>
558          /// Performs a non-indexed draw with the specified topology, index and count,
559          /// while incrementing the current instance.
560          /// </summary>
561          /// <param name="argument">Method call argument</param>
562          private void DrawVertexArrayBeginEndInstanceSubsequent(int argument)
563          {
564              _drawManager.DrawVertexArrayBeginEndInstanceSubsequent(this, argument);
565          }
566  
567          /// <summary>
568          /// Pushes four 8-bit index buffer elements.
569          /// </summary>
570          /// <param name="argument">Method call argument</param>
571          private void VbElementU8(int argument)
572          {
573              _drawManager.VbElementU8(argument);
574          }
575  
576          /// <summary>
577          /// Pushes two 16-bit index buffer elements.
578          /// </summary>
579          /// <param name="argument">Method call argument</param>
580          private void VbElementU16(int argument)
581          {
582              _drawManager.VbElementU16(argument);
583          }
584  
585          /// <summary>
586          /// Pushes one 32-bit index buffer element.
587          /// </summary>
588          /// <param name="argument">Method call argument</param>
589          private void VbElementU32(int argument)
590          {
591              _drawManager.VbElementU32(argument);
592          }
593  
594          /// <summary>
595          /// Resets the value of an internal GPU counter back to zero.
596          /// </summary>
597          /// <param name="argument">Method call argument</param>
598          private void ResetCounter(int argument)
599          {
600              _semaphoreUpdater.ResetCounter(argument);
601          }
602  
603          /// <summary>
604          /// Finishes the draw call.
605          /// This draws geometry on the bound buffers based on the current GPU state.
606          /// </summary>
607          /// <param name="argument">Method call argument</param>
608          private void DrawEnd(int argument)
609          {
610              _drawManager.DrawEnd(this, argument);
611          }
612  
613          /// <summary>
614          /// Starts draw.
615          /// This sets primitive type and instanced draw parameters.
616          /// </summary>
617          /// <param name="argument">Method call argument</param>
618          private void DrawBegin(int argument)
619          {
620              _drawManager.DrawBegin(this, argument);
621          }
622  
623          /// <summary>
624          /// Sets the index buffer count.
625          /// This also sets internal state that indicates that the next draw is an indexed draw.
626          /// </summary>
627          /// <param name="argument">Method call argument</param>
628          private void SetIndexBufferCount(int argument)
629          {
630              _drawManager.SetIndexBufferCount(argument);
631          }
632  
633          /// <summary>
634          /// Performs a indexed draw with 8-bit index buffer elements.
635          /// </summary>
636          /// <param name="argument">Method call argument</param>
637          private void DrawIndexBuffer8BeginEndInstanceFirst(int argument)
638          {
639              _drawManager.DrawIndexBuffer8BeginEndInstanceFirst(this, argument);
640          }
641  
642          /// <summary>
643          /// Performs a indexed draw with 16-bit index buffer elements.
644          /// </summary>
645          /// <param name="argument">Method call argument</param>
646          private void DrawIndexBuffer16BeginEndInstanceFirst(int argument)
647          {
648              _drawManager.DrawIndexBuffer16BeginEndInstanceFirst(this, argument);
649          }
650  
651          /// <summary>
652          /// Performs a indexed draw with 32-bit index buffer elements.
653          /// </summary>
654          /// <param name="argument">Method call argument</param>
655          private void DrawIndexBuffer32BeginEndInstanceFirst(int argument)
656          {
657              _drawManager.DrawIndexBuffer32BeginEndInstanceFirst(this, argument);
658          }
659  
660          /// <summary>
661          /// Performs a indexed draw with 8-bit index buffer elements,
662          /// while also pre-incrementing the current instance value.
663          /// </summary>
664          /// <param name="argument">Method call argument</param>
665          private void DrawIndexBuffer8BeginEndInstanceSubsequent(int argument)
666          {
667              _drawManager.DrawIndexBuffer8BeginEndInstanceSubsequent(this, argument);
668          }
669  
670          /// <summary>
671          /// Performs a indexed draw with 16-bit index buffer elements,
672          /// while also pre-incrementing the current instance value.
673          /// </summary>
674          /// <param name="argument">Method call argument</param>
675          private void DrawIndexBuffer16BeginEndInstanceSubsequent(int argument)
676          {
677              _drawManager.DrawIndexBuffer16BeginEndInstanceSubsequent(this, argument);
678          }
679  
680          /// <summary>
681          /// Performs a indexed draw with 32-bit index buffer elements,
682          /// while also pre-incrementing the current instance value.
683          /// </summary>
684          /// <param name="argument">Method call argument</param>
685          private void DrawIndexBuffer32BeginEndInstanceSubsequent(int argument)
686          {
687              _drawManager.DrawIndexBuffer32BeginEndInstanceSubsequent(this, argument);
688          }
689  
690          /// <summary>
691          /// Clears the current color and depth-stencil buffers.
692          /// Which buffers should be cleared is also specified on the argument.
693          /// </summary>
694          /// <param name="argument">Method call argument</param>
695          private void Clear(int argument)
696          {
697              _drawManager.Clear(this, argument);
698          }
699  
700          /// <summary>
701          /// Writes a GPU counter to guest memory.
702          /// </summary>
703          /// <param name="argument">Method call argument</param>
704          private void Report(int argument)
705          {
706              _semaphoreUpdater.Report(argument);
707          }
708  
709          /// <summary>
710          /// Performs high-level emulation of Falcon microcode function number "4".
711          /// </summary>
712          /// <param name="argument">Method call argument</param>
713          private void SetFalcon04(int argument)
714          {
715              _state.State.SetMmeShadowScratch[0] = 1;
716          }
717  
718          /// <summary>
719          /// Updates the uniform buffer data with inline data.
720          /// </summary>
721          /// <param name="argument">New uniform buffer data word</param>
722          private void ConstantBufferUpdate(int argument)
723          {
724              _cbUpdater.Update(argument);
725          }
726  
727          /// <summary>
728          /// Binds a uniform buffer for the vertex shader stage.
729          /// </summary>
730          /// <param name="argument">Method call argument</param>
731          private void ConstantBufferBindVertex(int argument)
732          {
733              _cbUpdater.BindVertex(argument);
734          }
735  
736          /// <summary>
737          /// Binds a uniform buffer for the tessellation control shader stage.
738          /// </summary>
739          /// <param name="argument">Method call argument</param>
740          private void ConstantBufferBindTessControl(int argument)
741          {
742              _cbUpdater.BindTessControl(argument);
743          }
744  
745          /// <summary>
746          /// Binds a uniform buffer for the tessellation evaluation shader stage.
747          /// </summary>
748          /// <param name="argument">Method call argument</param>
749          private void ConstantBufferBindTessEvaluation(int argument)
750          {
751              _cbUpdater.BindTessEvaluation(argument);
752          }
753  
754          /// <summary>
755          /// Binds a uniform buffer for the geometry shader stage.
756          /// </summary>
757          /// <param name="argument">Method call argument</param>
758          private void ConstantBufferBindGeometry(int argument)
759          {
760              _cbUpdater.BindGeometry(argument);
761          }
762  
763          /// <summary>
764          /// Binds a uniform buffer for the fragment shader stage.
765          /// </summary>
766          /// <param name="argument">Method call argument</param>
767          private void ConstantBufferBindFragment(int argument)
768          {
769              _cbUpdater.BindFragment(argument);
770          }
771  
772          /// <summary>
773          /// Generic register read function that just returns 0.
774          /// </summary>
775          /// <returns>Zero</returns>
776          private static int Zero()
777          {
778              return 0;
779          }
780  
781          /// <summary>
782          /// Performs a indexed or non-indexed draw.
783          /// </summary>
784          /// <param name="topology">Primitive topology</param>
785          /// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param>
786          /// <param name="instanceCount">Instance count</param>
787          /// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param>
788          /// <param name="firstVertex">First vertex on the vertex buffer</param>
789          /// <param name="firstInstance">First instance</param>
790          /// <param name="indexed">True if the draw is indexed, false otherwise</param>
791          public void Draw(
792              PrimitiveTopology topology,
793              int count,
794              int instanceCount,
795              int firstIndex,
796              int firstVertex,
797              int firstInstance,
798              bool indexed)
799          {
800              _drawManager.Draw(this, topology, count, instanceCount, firstIndex, firstVertex, firstInstance, indexed);
801          }
802  
803          /// <summary>
804          /// Performs a indirect draw, with parameters from a GPU buffer.
805          /// </summary>
806          /// <param name="topology">Primitive topology</param>
807          /// <param name="indirectBufferRange">Memory range of the buffer with the draw parameters, such as count, first index, etc</param>
808          /// <param name="parameterBufferRange">Memory range of the buffer with the draw count</param>
809          /// <param name="maxDrawCount">Maximum number of draws that can be made</param>
810          /// <param name="stride">Distance in bytes between each entry on the data pointed to by <paramref name="indirectBufferRange"/></param>
811          /// <param name="indexCount">Maximum number of indices that the draw can consume</param>
812          /// <param name="drawType">Type of the indirect draw, which can be indexed or non-indexed, with or without a draw count</param>
813          public void DrawIndirect(
814              PrimitiveTopology topology,
815              MultiRange indirectBufferRange,
816              MultiRange parameterBufferRange,
817              int maxDrawCount,
818              int stride,
819              int indexCount,
820              IndirectDrawType drawType)
821          {
822              _drawManager.DrawIndirect(this, topology, indirectBufferRange, parameterBufferRange, maxDrawCount, stride, indexCount, drawType);
823          }
824  
825          /// <summary>
826          /// Clears the current color and depth-stencil buffers.
827          /// Which buffers should be cleared can also specified with the arguments.
828          /// </summary>
829          /// <param name="argument">Method call argument</param>
830          /// <param name="layerCount">For array and 3D textures, indicates how many layers should be cleared</param>
831          public void Clear(int argument, int layerCount)
832          {
833              _drawManager.Clear(this, argument, layerCount);
834          }
835  
836          protected virtual void Dispose(bool disposing)
837          {
838              if (disposing)
839              {
840                  _drawManager.Dispose();
841              }
842          }
843  
844          public void Dispose()
845          {
846              Dispose(true);
847              GC.SuppressFinalize(this);
848          }
849      }
850  }