diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs index f3f8d3ca35..50aac1d074 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs @@ -10,6 +10,11 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { + /// + /// Dispatches compute work. + /// + /// Current GPU state + /// Method call argument public void Dispatch(GpuState state, int argument) { uint dispatchParamsAddress = (uint)state.Get(MethodOffset.DispatchParamsAddress); diff --git a/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs b/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs index 5644ca818b..c19b43d81e 100644 --- a/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs +++ b/Ryujinx.Graphics.Gpu/Engine/ComputeParams.cs @@ -4,22 +4,36 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Engine { + /// + /// Compute uniform buffer parameters. + /// struct UniformBufferParams { public int AddressLow; public int AddressHighAndSize; + /// + /// Packs the split address to a 64-bits integer. + /// + /// Uniform buffer GPU virtual address public ulong PackAddress() { return (uint)AddressLow | ((ulong)(AddressHighAndSize & 0xff) << 32); } + /// + /// Unpacks the uniform buffer size in bytes. + /// + /// Uniform buffer size in bytes public ulong UnpackSize() { return (ulong)((AddressHighAndSize >> 15) & 0x1ffff); } } + /// + /// Compute dispatch parameters. + /// struct ComputeParams { public int Unknown0; @@ -61,6 +75,9 @@ namespace Ryujinx.Graphics.Gpu.Engine private UniformBufferParams _uniformBuffer6; private UniformBufferParams _uniformBuffer7; + /// + /// Uniform buffer parameters. + /// public Span UniformBuffers { get @@ -89,36 +106,65 @@ namespace Ryujinx.Graphics.Gpu.Engine public int Unknown62; public int Unknown63; + /// + /// Unpacks the work group X size. + /// + /// Work group X size public int UnpackGridSizeX() { return GridSizeX & 0x7fffffff; } + /// + /// Unpacks the work group Y size. + /// + /// Work group Y size public int UnpackGridSizeY() { return GridSizeYZ & 0xffff; } + /// + /// Unpacks the work group Z size. + /// + /// Work group Z size public int UnpackGridSizeZ() { return (GridSizeYZ >> 16) & 0xffff; } + /// + /// Unpacks the local group X size. + /// + /// Local group X size public int UnpackBlockSizeX() { return (BlockSizeX >> 16) & 0xffff; } + /// + /// Unpacks the local group Y size. + /// + /// Local group Y size public int UnpackBlockSizeY() { return BlockSizeYZ & 0xffff; } + /// + /// Unpacks the local group Z size. + /// + /// Local group Z size public int UnpackBlockSizeZ() { return (BlockSizeYZ >> 16) & 0xffff; } + /// + /// Unpacks the uniform buffers enable mask. + /// Each bit set on the mask indicates that the respective buffer index is enabled. + /// + /// Uniform buffers enable mask public uint UnpackUniformBuffersEnableMask() { return (uint)UniformBuffersConfig & 0xff; diff --git a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs index 8d1ebebe13..7943239568 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs @@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Engine private int[] _buffer; + /// + /// Launches Inline-to-Memory engine DMA copy. + /// + /// Current GPU state + /// Method call argument public void LaunchDma(GpuState state, int argument) { _params = state.Get(MethodOffset.I2mParams); @@ -42,6 +47,11 @@ namespace Ryujinx.Graphics.Gpu.Engine _finished = false; } + /// + /// Pushes a word of data to the Inline-to-Memory engine. + /// + /// Current GPU state + /// Method call argument public void LoadInlineData(GpuState state, int argument) { if (!_finished) @@ -55,6 +65,9 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Performs actual copy of the inline data after the transfer is finished. + /// private void FinishTransfer() { Span data = MemoryMarshal.Cast(_buffer).Slice(0, _size); diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs index 906ae22552..dfa7b12ed3 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs @@ -5,6 +5,12 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { + /// + /// Clears the current color and depth-stencil buffers. + /// Which buffers should be cleared is also specified on the argument. + /// + /// Current GPU state + /// Method call argument private void Clear(GpuState state, int argument) { UpdateRenderTargetState(state, useControl: false); diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs index 1f84916a18..6b6742ff10 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyBuffer.cs @@ -6,6 +6,11 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { + /// + /// Performs a buffer to buffer, or buffer to texture copy. + /// + /// Current GPU state + /// Method call argument private void CopyBuffer(GpuState state, int argument) { var cbp = state.Get(MethodOffset.CopyBufferParams); diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs index cdfd36df41..8d1b2b714f 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs @@ -7,6 +7,11 @@ namespace Ryujinx.Graphics.Gpu.Engine partial class Methods { + /// + /// Performs a texture to texture copy. + /// + /// Current GPU state + /// Method call argument private void CopyTexture(GpuState state, int argument) { var dstCopyTexture = state.Get(MethodOffset.CopyDstTexture); diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs index 5c5a1deeb2..d2571d3d73 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs @@ -22,8 +22,17 @@ namespace Ryujinx.Graphics.Gpu.Engine private int _instanceIndex; + /// + /// Primitive type of the current draw. + /// public PrimitiveType PrimitiveType { get; private set; } + /// + /// Finishes draw call. + /// This draws geometry on the bound buffers based on the current GPU state. + /// + /// Current GPU state + /// Method call argument private void DrawEnd(GpuState state, int argument) { if (_instancedDrawPending) @@ -86,6 +95,12 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Starts draw. + /// This sets primitive type and instanced draw parameters. + /// + /// Current GPU state + /// Method call argument private void DrawBegin(GpuState state, int argument) { if ((argument & (1 << 26)) != 0) @@ -106,11 +121,24 @@ namespace Ryujinx.Graphics.Gpu.Engine PrimitiveType = type; } + /// + /// Sets the index buffer count. + /// This also sets internal state that indicates that the next draw is a indexed draw. + /// + /// Current GPU state + /// Method call argument private void SetIndexBufferCount(GpuState state, int argument) { _drawIndexed = true; } + /// + /// Perform any deferred draws. + /// This is used for instanced draws. + /// Since each instance is a separate draw, we defer the draw and accumulate the instance count. + /// Once we detect the last instanced draw, then we perform the host instanced draw, + /// with the accumulated instance count. + /// public void PerformDeferredDraws() { // Perform any pending instanced draw. diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs b/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs index f73c03cb97..8418f0bb57 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs @@ -10,6 +10,11 @@ namespace Ryujinx.Graphics.Gpu.Engine { private ulong _runningCounter; + /// + /// Writes a GPU counter to guest memory. + /// + /// Current GPU state + /// Method call argument private void Report(GpuState state, int argument) { ReportMode mode = (ReportMode)(argument & 3); @@ -23,6 +28,10 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Writes a GPU semaphore value to guest memory. + /// + /// Current GPU state private void ReportSemaphore(GpuState state) { var rs = state.Get(MethodOffset.ReportState); @@ -32,12 +41,21 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.AdvanceSequence(); } + /// + /// Packed GPU counter data (including GPU timestamp) in memory. + /// private struct CounterData { public ulong Counter; public ulong Timestamp; } + /// + /// Writes a GPU counter to guest memory. + /// This also writes the current timestamp value. + /// + /// Current GPU state + /// Counter to be written to memory private void ReportCounter(GpuState state, ReportCounterType type) { CounterData counterData = new CounterData(); @@ -83,6 +101,12 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.MemoryAccessor.Write(rs.Address.Pack(), data); } + /// + /// Converts a nanoseconds timestamp value to Maxwell time ticks. + /// The frequency is approximately 1.63Hz. + /// + /// Timestamp in nanoseconds + /// Maxwell ticks private static ulong ConvertNanosecondsToTicks(ulong nanoseconds) { // We need to divide first to avoid overflows. diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs b/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs index 574eb5c8f0..9b46908205 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs @@ -5,6 +5,11 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { + /// + /// Resets the value of a internal GPU counter back to zero. + /// + /// Current GPU state + /// Method call argument private void ResetCounter(GpuState state, int argument) { ResetCounterType type = (ResetCounterType)argument; diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs index 6232c0b6cf..3fee1fcf8b 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs @@ -4,31 +4,62 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { + /// + /// Binds a uniform buffer for the vertex shader stage. + /// + /// Current GPU state + /// Method call argument private void UniformBufferBindVertex(GpuState state, int argument) { UniformBufferBind(state, argument, ShaderType.Vertex); } + /// + /// Binds a uniform buffer for the tessellation control shader stage. + /// + /// Current GPU state + /// Method call argument private void UniformBufferBindTessControl(GpuState state, int argument) { UniformBufferBind(state, argument, ShaderType.TessellationControl); } + /// + /// Binds a uniform buffer for the tessellation evaluation shader stage. + /// + /// Current GPU state + /// Method call argument private void UniformBufferBindTessEvaluation(GpuState state, int argument) { UniformBufferBind(state, argument, ShaderType.TessellationEvaluation); } + /// + /// Binds a uniform buffer for the geometry shader stage. + /// + /// Current GPU state + /// Method call argument private void UniformBufferBindGeometry(GpuState state, int argument) { UniformBufferBind(state, argument, ShaderType.Geometry); } + /// + /// Binds a uniform buffer for the fragment shader stage. + /// + /// Current GPU state + /// Method call argument private void UniformBufferBindFragment(GpuState state, int argument) { UniformBufferBind(state, argument, ShaderType.Fragment); } + /// + ///Binds a uniform buffer for the specified shader stage. + /// + /// Current GPU state + /// Method call argument + /// Shader stage that will access the uniform buffer private void UniformBufferBind(GpuState state, int argument, ShaderType type) { bool enable = (argument & 1) != 0; diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs index 43bab2433b..524f5e0399 100644 --- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs +++ b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs @@ -4,6 +4,11 @@ namespace Ryujinx.Graphics.Gpu.Engine { partial class Methods { + /// + /// Updates the uniform buffer data with inline data. + /// + /// Current GPU state + /// New uniform buffer data word private void UniformBufferUpdate(GpuState state, int argument) { var uniformBuffer = state.Get(MethodOffset.UniformBufferState); diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index 35f09ad318..0a52bee9ac 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -12,6 +12,9 @@ namespace Ryujinx.Graphics.Gpu.Engine { using Texture = Image.Texture; + /// + /// GPU method implementations. + /// partial class Methods { private readonly GpuContext _context; @@ -20,12 +23,23 @@ namespace Ryujinx.Graphics.Gpu.Engine private readonly ShaderProgramInfo[] _currentProgramInfo; - public BufferManager BufferManager { get; } + /// + /// GPU buffer manager. + /// + public BufferManager BufferManager { get; } + + /// + /// GPU texture manager. + /// public TextureManager TextureManager { get; } private bool _isAnyVbInstanced; private bool _vsUsesInstanceId; + /// + /// Creates a new instance of the GPU methods class. + /// + /// GPU context public Methods(GpuContext context) { _context = context; @@ -38,6 +52,10 @@ namespace Ryujinx.Graphics.Gpu.Engine TextureManager = new TextureManager(context); } + /// + /// Register callback for GPU method calls that triggers an action on the GPU. + /// + /// GPU state where the triggers will be registered public void RegisterCallbacks(GpuState state) { state.RegisterCallback(MethodOffset.LaunchDma, LaunchDma); @@ -72,6 +90,10 @@ namespace Ryujinx.Graphics.Gpu.Engine state.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment); } + /// + /// Updates host state based on the current guest GPU state. + /// + /// Guest GPU state private void UpdateState(GpuState state) { // Shaders must be the first one to be updated if modified, because @@ -175,6 +197,10 @@ namespace Ryujinx.Graphics.Gpu.Engine CommitBindings(); } + /// + /// Ensures that the bindings are visible to the host GPU. + /// This actually performs the binding using the host graphics API. + /// private void CommitBindings() { UpdateStorageBuffers(); @@ -183,6 +209,9 @@ namespace Ryujinx.Graphics.Gpu.Engine TextureManager.CommitGraphicsBindings(); } + /// + /// Updates storage buffer bindings. + /// private void UpdateStorageBuffers() { for (int stage = 0; stage < _currentProgramInfo.Length; stage++) @@ -213,6 +242,11 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Updates render targets (color and depth-stencil buffers) based on current render target state. + /// + /// Current GPU state + /// Use draw buffers information from render target control register private void UpdateRenderTargetState(GpuState state, bool useControl) { var rtControl = state.Get(MethodOffset.RtControl); @@ -267,12 +301,21 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Checks if a render target color buffer is used. + /// + /// Color buffer information + /// True if the specified buffer is enabled/used, false otherwise private static bool IsRtEnabled(RtColorState colorState) { // Colors are disabled by writing 0 to the format. return colorState.Format != 0 && colorState.WidthOrStride != 0; } + /// + /// Updates host depth test state based on current GPU state. + /// + /// Current GPU state private void UpdateDepthTestState(GpuState state) { _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor( @@ -281,6 +324,10 @@ namespace Ryujinx.Graphics.Gpu.Engine state.Get(MethodOffset.DepthTestFunc))); } + /// + /// Updates host viewport transform and clipping state based on current GPU state. + /// + /// Current GPU state private void UpdateViewportTransform(GpuState state) { DepthMode depthMode = state.Get(MethodOffset.DepthMode); @@ -343,6 +390,10 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetViewports(0, viewports); } + /// + /// Updates host depth bias (also called polygon offset) state based on current GPU state. + /// + /// Current GPU state private void UpdateDepthBiasState(GpuState state) { var depthBias = state.Get(MethodOffset.DepthBiasState); @@ -360,6 +411,10 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetDepthBias(enables, factor, units, clamp); } + /// + /// Updates host stencil test state based on current GPU state. + /// + /// Current GPU state private void UpdateStencilTestState(GpuState state) { var backMasks = state.Get (MethodOffset.StencilBackMasks); @@ -413,6 +468,10 @@ namespace Ryujinx.Graphics.Gpu.Engine backMask)); } + /// + /// Updates current sampler pool address and size based on guest GPU state. + /// + /// Current GPU state private void UpdateSamplerPoolState(GpuState state) { var texturePool = state.Get(MethodOffset.TexturePoolState); @@ -427,6 +486,10 @@ namespace Ryujinx.Graphics.Gpu.Engine TextureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), maximumId, samplerIndex); } + /// + /// Updates current texture pool address and size based on guest GPU state. + /// + /// Current GPU state private void UpdateTexturePoolState(GpuState state) { var texturePool = state.Get(MethodOffset.TexturePoolState); @@ -436,6 +499,10 @@ namespace Ryujinx.Graphics.Gpu.Engine TextureManager.SetGraphicsTextureBufferIndex(state.Get(MethodOffset.TextureBufferIndex)); } + /// + /// Updates host vertex attributes based on guest GPU state. + /// + /// Current GPU state private void UpdateVertexAttribState(GpuState state) { VertexAttribDescriptor[] vertexAttribs = new VertexAttribDescriptor[16]; @@ -460,6 +527,10 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs); } + /// + /// Updates host primitive restart based on guest GPU state. + /// + /// Current GPU state private void UpdatePrimitiveRestartState(GpuState state) { PrimitiveRestartState primitiveRestart = state.Get(MethodOffset.PrimitiveRestartState); @@ -469,6 +540,10 @@ namespace Ryujinx.Graphics.Gpu.Engine primitiveRestart.Index); } + /// + /// Updates host index buffer binding based on guest GPU state. + /// + /// Current GPU state private void UpdateIndexBufferState(GpuState state) { var indexBuffer = state.Get(MethodOffset.IndexBufferState); @@ -500,6 +575,10 @@ namespace Ryujinx.Graphics.Gpu.Engine UpdateVertexBufferState(state); } + /// + /// Updates host vertex buffer bindings based on guest GPU state. + /// + /// Current GPU state private void UpdateVertexBufferState(GpuState state) { _isAnyVbInstanced = false; @@ -550,6 +629,10 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Updates host face culling and orientation based on guest GPU state. + /// + /// Current GPU state private void UpdateFaceState(GpuState state) { var face = state.Get(MethodOffset.FaceState); @@ -559,6 +642,11 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetFrontFace(face.FrontFace); } + /// + /// Updates host render target color masks, based on guest GPU state. + /// This defines with color channels are written to each color buffer. + /// + /// Current GPU state private void UpdateRtColorMask(GpuState state) { bool rtColorMaskShared = state.Get(MethodOffset.RtColorMaskShared); @@ -582,6 +670,10 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks); } + /// + /// Updates host render target color buffer blending state, based on guest state. + /// + /// Current GPU state private void UpdateBlendState(GpuState state) { bool blendIndependent = state.Get(MethodOffset.BlendIndependent); @@ -623,6 +715,9 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Storage buffer address and size information. + /// private struct SbDescriptor { public uint AddressLow; @@ -636,6 +731,10 @@ namespace Ryujinx.Graphics.Gpu.Engine } } + /// + /// Updates host shaders based on the guest GPU state. + /// + /// Current GPU state private void UpdateShaderState(GpuState state) { ShaderAddresses addresses = new ShaderAddresses(); @@ -726,6 +825,11 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetProgram(gs.HostProgram); } + /// + /// Gets viewport transform enable. + /// + /// Current GPU state + /// Viewport transform enable public bool GetViewportTransformEnable(GpuState state) { // FIXME: We should read ViewportTransformEnable, but it seems that some games writes 0 there? @@ -734,6 +838,11 @@ namespace Ryujinx.Graphics.Gpu.Engine return true; } + /// + /// Gets texture target from a sampler type. + /// + /// Sampler type + /// Texture target value private static Target GetTarget(SamplerType type) { type &= ~(SamplerType.Indexed | SamplerType.Shadow); @@ -776,16 +885,38 @@ namespace Ryujinx.Graphics.Gpu.Engine return Target.Texture2D; } + /// + /// Issues a texture barrier. + /// This waits until previous texture writes from the GPU to finish, before + /// performing new operations with said textures. + /// + /// Current GPU state + /// Method call argument private void TextureBarrier(GpuState state, int argument) { _context.Renderer.Pipeline.TextureBarrier(); } + /// + /// Invalidates all modified textures on the cache. + /// + /// Current GPU state + /// Method call argument private void InvalidateTextures(GpuState state, int argument) { TextureManager.Flush(); } + /// + /// Issues a texture barrier. + /// This waits until previous texture writes from the GPU to finish, before + /// performing new operations with said textures. + /// This performs a per-tile wait, it is only valid if both the previous write + /// and current access has the same access patterns. + /// This may be faster than the regular barrier on tile-based rasterizers. + /// + /// + /// private void TextureBarrierTiled(GpuState state, int argument) { _context.Renderer.Pipeline.TextureBarrierTiled();