Compute.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. using Ryujinx.Graphics.GAL;
  2. using Ryujinx.Graphics.Gpu.Image;
  3. using Ryujinx.Graphics.Gpu.Shader;
  4. using Ryujinx.Graphics.Gpu.State;
  5. using Ryujinx.Graphics.Shader;
  6. using System;
  7. using System.Runtime.InteropServices;
  8. namespace Ryujinx.Graphics.Gpu.Engine
  9. {
  10. partial class Methods
  11. {
  12. /// <summary>
  13. /// Dispatches compute work.
  14. /// </summary>
  15. /// <param name="state">Current GPU state</param>
  16. /// <param name="argument">Method call argument</param>
  17. public void Dispatch(GpuState state, int argument)
  18. {
  19. uint qmdAddress = (uint)state.Get<int>(MethodOffset.DispatchParamsAddress);
  20. var qmd = _context.MemoryAccessor.Read<ComputeQmd>((ulong)qmdAddress << 8);
  21. GpuVa shaderBaseAddress = state.Get<GpuVa>(MethodOffset.ShaderBaseAddress);
  22. ulong shaderGpuVa = shaderBaseAddress.Pack() + (uint)qmd.ProgramOffset;
  23. int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;
  24. int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);
  25. uint sbEnableMask = 0;
  26. uint ubEnableMask = 0;
  27. for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
  28. {
  29. if (!qmd.ConstantBufferValid(index))
  30. {
  31. continue;
  32. }
  33. ubEnableMask |= 1u << index;
  34. ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
  35. ulong size = (ulong)qmd.ConstantBufferSize(index);
  36. BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
  37. }
  38. ShaderBundle cs = ShaderCache.GetComputeShader(
  39. state,
  40. shaderGpuVa,
  41. qmd.CtaThreadDimension0,
  42. qmd.CtaThreadDimension1,
  43. qmd.CtaThreadDimension2,
  44. localMemorySize,
  45. sharedMemorySize);
  46. _context.Renderer.Pipeline.SetProgram(cs.HostProgram);
  47. var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState);
  48. TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex);
  49. var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
  50. TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
  51. TextureManager.SetComputeTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
  52. ShaderProgramInfo info = cs.Shaders[0].Program.Info;
  53. for (int index = 0; index < info.CBuffers.Count; index++)
  54. {
  55. BufferDescriptor cb = info.CBuffers[index];
  56. // NVN uses the "hardware" constant buffer for anything that is less than 8,
  57. // and those are already bound above.
  58. // Anything greater than or equal to 8 uses the emulated constant buffers.
  59. // They are emulated using global memory loads.
  60. if (cb.Slot < 8)
  61. {
  62. continue;
  63. }
  64. ubEnableMask |= 1u << cb.Slot;
  65. ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);
  66. int cbDescOffset = 0x260 + cb.Slot * 0x10;
  67. cbDescAddress += (ulong)cbDescOffset;
  68. ReadOnlySpan<byte> cbDescriptorData = _context.PhysicalMemory.GetSpan(cbDescAddress, 0x10);
  69. SbDescriptor cbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(cbDescriptorData)[0];
  70. BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
  71. }
  72. for (int index = 0; index < info.SBuffers.Count; index++)
  73. {
  74. BufferDescriptor sb = info.SBuffers[index];
  75. sbEnableMask |= 1u << sb.Slot;
  76. ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0);
  77. int sbDescOffset = 0x310 + sb.Slot * 0x10;
  78. sbDescAddress += (ulong)sbDescOffset;
  79. ReadOnlySpan<byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);
  80. SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
  81. BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
  82. }
  83. ubEnableMask = 0;
  84. for (int index = 0; index < info.CBuffers.Count; index++)
  85. {
  86. ubEnableMask |= 1u << info.CBuffers[index].Slot;
  87. }
  88. BufferManager.SetComputeStorageBufferEnableMask(sbEnableMask);
  89. BufferManager.SetComputeUniformBufferEnableMask(ubEnableMask);
  90. var textureBindings = new TextureBindingInfo[info.Textures.Count];
  91. for (int index = 0; index < info.Textures.Count; index++)
  92. {
  93. var descriptor = info.Textures[index];
  94. Target target = GetTarget(descriptor.Type);
  95. if (descriptor.IsBindless)
  96. {
  97. textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufOffset, descriptor.CbufSlot);
  98. }
  99. else
  100. {
  101. textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
  102. }
  103. }
  104. TextureManager.SetComputeTextures(textureBindings);
  105. var imageBindings = new TextureBindingInfo[info.Images.Count];
  106. for (int index = 0; index < info.Images.Count; index++)
  107. {
  108. var descriptor = info.Images[index];
  109. Target target = GetTarget(descriptor.Type);
  110. imageBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex);
  111. }
  112. TextureManager.SetComputeImages(imageBindings);
  113. BufferManager.CommitComputeBindings();
  114. TextureManager.CommitComputeBindings();
  115. _context.Renderer.Pipeline.DispatchCompute(
  116. qmd.CtaRasterWidth,
  117. qmd.CtaRasterHeight,
  118. qmd.CtaRasterDepth);
  119. UpdateShaderState(state);
  120. }
  121. }
  122. }