aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-07-07 20:56:06 -0300
committerGitHub <noreply@github.com>2021-07-07 20:56:06 -0300
commit8b44eb1c981d7106be37107755c7c71c3c3c0ce4 (patch)
tree70c3a8d7286d827941c41dee2ec3cb3273c1e6d7 /Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
parent31cbd09a75a9d5f4814c3907a060e0961eb2bb15 (diff)
Separate GPU engines and make state follow official docs (part 1/2) (#2422)
* Use DeviceState for compute and i2m * Migrate 2D class, more comments * Migrate DMA copy engine * Remove now unused code * Replace GpuState by GpuAccessorState on GpuAcessor, since compute no longer has a GpuState * More comments * Add logging (disabled) * Add back i2m on 3D engine
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs213
1 files changed, 213 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
new file mode 100644
index 00000000..5d1fd2c0
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
@@ -0,0 +1,213 @@
+using Ryujinx.Graphics.Device;
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
+using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Gpu.Shader;
+using Ryujinx.Graphics.Gpu.State;
+using Ryujinx.Graphics.Shader;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Graphics.Gpu.Engine.Compute
+{
+ /// <summary>
+ /// Represents a compute engine class.
+ /// </summary>
+ class ComputeClass : InlineToMemoryClass, IDeviceState
+ {
+ private readonly GpuContext _context;
+ private readonly GpuChannel _channel;
+ private readonly DeviceState<ComputeClassState> _state;
+
+ /// <summary>
+ /// Creates a new instance of the compute engine class.
+ /// </summary>
+ /// <param name="context">GPU context</param>
+ /// <param name="channel">GPU channel</param>
+ public ComputeClass(GpuContext context, GpuChannel channel) : base(context, channel, false)
+ {
+ _context = context;
+ _channel = channel;
+ _state = new DeviceState<ComputeClassState>(new Dictionary<string, RwCallback>
+ {
+ { nameof(ComputeClassState.LaunchDma), new RwCallback(LaunchDma, null) },
+ { nameof(ComputeClassState.LoadInlineData), new RwCallback(LoadInlineData, null) },
+ { nameof(ComputeClassState.SendSignalingPcasB), new RwCallback(SendSignalingPcasB, null) }
+ });
+ }
+
+ /// <summary>
+ /// Reads data from the class registers.
+ /// </summary>
+ /// <param name="offset">Register byte offset</param>
+ /// <returns>Data at the specified offset</returns>
+ public override int Read(int offset) => _state.Read(offset);
+
+ /// <summary>
+ /// Writes data to the class registers.
+ /// </summary>
+ /// <param name="offset">Register byte offset</param>
+ /// <param name="data">Data to be written</param>
+ public override void Write(int offset, int data) => _state.Write(offset, data);
+
+ /// <summary>
+ /// Launches the Inline-to-Memory DMA copy operation.
+ /// </summary>
+ /// <param name="argument">Method call argument</param>
+ protected override void LaunchDma(int argument)
+ {
+ LaunchDma(ref Unsafe.As<ComputeClassState, InlineToMemoryClassState>(ref _state.State), argument);
+ }
+
+ /// <summary>
+ /// Performs the compute dispatch operation.
+ /// </summary>
+ /// <param name="argument">Method call argument</param>
+ private void SendSignalingPcasB(int argument)
+ {
+ var memoryManager = _channel.MemoryManager;
+
+ _context.Methods.FlushUboDirty(memoryManager);
+
+ uint qmdAddress = _state.State.SendPcasA;
+
+ var qmd = _channel.MemoryManager.Read<ComputeQmd>((ulong)qmdAddress << 8);
+
+ ulong shaderGpuVa = ((ulong)_state.State.SetProgramRegionAAddressUpper << 32) | _state.State.SetProgramRegionB;
+
+ shaderGpuVa += (uint)qmd.ProgramOffset;
+
+ int localMemorySize = qmd.ShaderLocalMemoryLowSize + qmd.ShaderLocalMemoryHighSize;
+
+ int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize);
+
+ for (int index = 0; index < Constants.TotalCpUniformBuffers; index++)
+ {
+ if (!qmd.ConstantBufferValid(index))
+ {
+ continue;
+ }
+
+ ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32;
+ ulong size = (ulong)qmd.ConstantBufferSize(index);
+
+ _channel.BufferManager.SetComputeUniformBuffer(index, gpuVa, size);
+ }
+
+ ulong samplerPoolGpuVa = ((ulong)_state.State.SetTexSamplerPoolAOffsetUpper << 32) | _state.State.SetTexSamplerPoolB;
+ ulong texturePoolGpuVa = ((ulong)_state.State.SetTexHeaderPoolAOffsetUpper << 32) | _state.State.SetTexHeaderPoolB;
+
+ GpuAccessorState gas = new GpuAccessorState(
+ texturePoolGpuVa,
+ _state.State.SetTexHeaderPoolCMaximumIndex,
+ _state.State.SetBindlessTextureConstantBufferSlotSelect,
+ false);
+
+ ShaderBundle cs = memoryManager.Physical.ShaderCache.GetComputeShader(
+ _channel,
+ gas,
+ shaderGpuVa,
+ qmd.CtaThreadDimension0,
+ qmd.CtaThreadDimension1,
+ qmd.CtaThreadDimension2,
+ localMemorySize,
+ sharedMemorySize);
+
+ _context.Renderer.Pipeline.SetProgram(cs.HostProgram);
+
+ _channel.TextureManager.SetComputeSamplerPool(samplerPoolGpuVa, _state.State.SetTexSamplerPoolCMaximumIndex, qmd.SamplerIndex);
+ _channel.TextureManager.SetComputeTexturePool(texturePoolGpuVa, _state.State.SetTexHeaderPoolCMaximumIndex);
+ _channel.TextureManager.SetComputeTextureBufferIndex(_state.State.SetBindlessTextureConstantBufferSlotSelect);
+
+ ShaderProgramInfo info = cs.Shaders[0].Info;
+
+ for (int index = 0; index < info.CBuffers.Count; index++)
+ {
+ BufferDescriptor cb = info.CBuffers[index];
+
+ // NVN uses the "hardware" constant buffer for anything that is less than 8,
+ // and those are already bound above.
+ // Anything greater than or equal to 8 uses the emulated constant buffers.
+ // They are emulated using global memory loads.
+ if (cb.Slot < 8)
+ {
+ continue;
+ }
+
+ ulong cbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);
+
+ int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10;
+
+ cbDescAddress += (ulong)cbDescOffset;
+
+ SbDescriptor cbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(cbDescAddress);
+
+ _channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
+ }
+
+ for (int index = 0; index < info.SBuffers.Count; index++)
+ {
+ BufferDescriptor sb = info.SBuffers[index];
+
+ ulong sbDescAddress = _channel.BufferManager.GetComputeUniformBufferAddress(0);
+
+ int sbDescOffset = 0x310 + sb.Slot * 0x10;
+
+ sbDescAddress += (ulong)sbDescOffset;
+
+ SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
+
+ _channel.BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
+ }
+
+ _channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
+ _channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
+
+ var textureBindings = new TextureBindingInfo[info.Textures.Count];
+
+ for (int index = 0; index < info.Textures.Count; index++)
+ {
+ var descriptor = info.Textures[index];
+
+ Target target = ShaderTexture.GetTarget(descriptor.Type);
+
+ textureBindings[index] = new TextureBindingInfo(
+ target,
+ descriptor.Binding,
+ descriptor.CbufSlot,
+ descriptor.HandleIndex,
+ descriptor.Flags);
+ }
+
+ _channel.TextureManager.SetComputeTextures(textureBindings);
+
+ var imageBindings = new TextureBindingInfo[info.Images.Count];
+
+ for (int index = 0; index < info.Images.Count; index++)
+ {
+ var descriptor = info.Images[index];
+
+ Target target = ShaderTexture.GetTarget(descriptor.Type);
+ Format format = ShaderTexture.GetFormat(descriptor.Format);
+
+ imageBindings[index] = new TextureBindingInfo(
+ target,
+ format,
+ descriptor.Binding,
+ descriptor.CbufSlot,
+ descriptor.HandleIndex,
+ descriptor.Flags);
+ }
+
+ _channel.TextureManager.SetComputeImages(imageBindings);
+
+ _channel.TextureManager.CommitComputeBindings();
+ _channel.BufferManager.CommitComputeBindings();
+
+ _context.Renderer.Pipeline.DispatchCompute(qmd.CtaRasterWidth, qmd.CtaRasterHeight, qmd.CtaRasterDepth);
+
+ _context.Methods.ForceShaderUpdate();
+ }
+ }
+}