aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine/Methods.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-07-11 17:20:40 -0300
committerGitHub <noreply@github.com>2021-07-11 17:20:40 -0300
commit40b21cc3c4d2622bbd4f88d43073341854d9a671 (patch)
tree6e9dc6a42e7c0bae5b03db468481771d5a6937ef /Ryujinx.Graphics.Gpu/Engine/Methods.cs
parentb5190f16810eb77388c861d1d1773e19644808db (diff)
Separate GPU engines (part 2/2) (#2440)
* 3D engine now uses DeviceState too, plus new state modification tracking * Remove old methods code * Remove GpuState and friends * Optimize DeviceState, force inline some functions * This change was not supposed to go in * Proper channel initialization * Optimize state read/write methods even more * Fix debug build * Do not dirty state if the write is redundant * The YControl register should dirty either the viewport or front face state too, to update the host origin * Avoid redundant vertex buffer updates * Move state and get rid of the Ryujinx.Graphics.Gpu.State namespace * Comments and nits * Fix rebase * PR feedback * Move changed = false to improve codegen * PR feedback * Carry RyuJIT a bit more
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine/Methods.cs')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs1138
1 files changed, 0 insertions, 1138 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
deleted file mode 100644
index 756d56d9..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ /dev/null
@@ -1,1138 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Image;
-using Ryujinx.Graphics.Gpu.Memory;
-using Ryujinx.Graphics.Gpu.Shader;
-using Ryujinx.Graphics.Gpu.State;
-using Ryujinx.Graphics.Shader;
-using Ryujinx.Graphics.Texture;
-using System;
-using System.Linq;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Gpu.Engine
-{
- using Texture = Image.Texture;
-
- /// <summary>
- /// GPU method implementations.
- /// </summary>
- partial class Methods
- {
- private readonly GpuContext _context;
- private readonly ShaderProgramInfo[] _currentProgramInfo;
-
- private bool _isAnyVbInstanced;
- private bool _vsUsesInstanceId;
- private byte _vsClipDistancesWritten;
-
- private bool _forceShaderUpdate;
-
- private bool _prevTfEnable;
-
- /// <summary>
- /// Creates a new instance of the GPU methods class.
- /// </summary>
- /// <param name="context">GPU context</param>
- public Methods(GpuContext context)
- {
- _context = context;
-
- _currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
- }
-
- /// <summary>
- /// Register callback for GPU method calls that triggers an action on the GPU.
- /// </summary>
- /// <param name="state">GPU state where the triggers will be registered</param>
- public void RegisterCallbacks(GpuState state)
- {
- state.RegisterCallback(MethodOffset.LaunchDma, LaunchDma);
- state.RegisterCallback(MethodOffset.LoadInlineData, LoadInlineData);
-
- state.RegisterCallback(MethodOffset.SyncpointAction, IncrementSyncpoint);
-
- state.RegisterCallback(MethodOffset.TextureBarrier, TextureBarrier);
- state.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
-
- state.RegisterCallback(MethodOffset.VbElementU8, VbElementU8);
- state.RegisterCallback(MethodOffset.VbElementU16, VbElementU16);
- state.RegisterCallback(MethodOffset.VbElementU32, VbElementU32);
-
- state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
-
- state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
- state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
- state.RegisterCallback(MethodOffset.DrawIndexedSmall, DrawIndexedSmall);
- state.RegisterCallback(MethodOffset.DrawIndexedSmall2, DrawIndexedSmall2);
- state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance, DrawIndexedSmallIncInstance);
- state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance2, DrawIndexedSmallIncInstance2);
-
- state.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
-
- state.RegisterCallback(MethodOffset.Clear, Clear);
-
- state.RegisterCallback(MethodOffset.Report, Report);
-
- state.RegisterCallback(MethodOffset.FirmwareCall4, FirmwareCall4);
-
- state.RegisterCallback(MethodOffset.UniformBufferUpdateData, 16, UniformBufferUpdate);
-
- state.RegisterCallback(MethodOffset.UniformBufferBindVertex, UniformBufferBindVertex);
- state.RegisterCallback(MethodOffset.UniformBufferBindTessControl, UniformBufferBindTessControl);
- state.RegisterCallback(MethodOffset.UniformBufferBindTessEvaluation, UniformBufferBindTessEvaluation);
- state.RegisterCallback(MethodOffset.UniformBufferBindGeometry, UniformBufferBindGeometry);
- state.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment);
- }
-
- /// <summary>
- /// Updates host state based on the current guest GPU state.
- /// </summary>
- /// <param name="state">Guest GPU state</param>
- /// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
- /// <param name="indexCount">Number of index buffer elements used on the draw</param>
- private void UpdateState(GpuState state, int firstIndex, int indexCount)
- {
- bool tfEnable = state.Get<Boolean32>(MethodOffset.TfEnable);
-
- if (!tfEnable && _prevTfEnable)
- {
- _context.Renderer.Pipeline.EndTransformFeedback();
- _prevTfEnable = false;
- }
-
- FlushUboDirty(state.Channel.MemoryManager);
-
- // Shaders must be the first one to be updated if modified, because
- // some of the other state depends on information from the currently
- // bound shaders.
- if (state.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState) || _forceShaderUpdate)
- {
- _forceShaderUpdate = false;
-
- UpdateShaderState(state);
- }
-
- if (state.QueryModified(MethodOffset.TfBufferState))
- {
- UpdateTfBufferState(state);
- }
-
- if (state.QueryModified(MethodOffset.ClipDistanceEnable))
- {
- UpdateUserClipState(state);
- }
-
- if (state.QueryModified(MethodOffset.RasterizeEnable))
- {
- UpdateRasterizerState(state);
- }
-
- if (state.QueryModified(MethodOffset.RtColorState,
- MethodOffset.RtDepthStencilState,
- MethodOffset.RtControl,
- MethodOffset.RtDepthStencilSize,
- MethodOffset.RtDepthStencilEnable))
- {
- UpdateRenderTargetState(state, useControl: true);
- }
-
- if (state.QueryModified(MethodOffset.ScissorState))
- {
- UpdateScissorState(state);
- }
-
- if (state.QueryModified(MethodOffset.ViewVolumeClipControl))
- {
- UpdateDepthClampState(state);
- }
-
- if (state.QueryModified(MethodOffset.AlphaTestEnable,
- MethodOffset.AlphaTestRef,
- MethodOffset.AlphaTestFunc))
- {
- UpdateAlphaTestState(state);
- }
-
- if (state.QueryModified(MethodOffset.DepthTestEnable,
- MethodOffset.DepthWriteEnable,
- MethodOffset.DepthTestFunc))
- {
- UpdateDepthTestState(state);
- }
-
- if (state.QueryModified(MethodOffset.DepthMode,
- MethodOffset.ViewportTransform,
- MethodOffset.ViewportExtents))
- {
- UpdateViewportTransform(state);
- }
-
- if (state.QueryModified(MethodOffset.DepthBiasState,
- MethodOffset.DepthBiasFactor,
- MethodOffset.DepthBiasUnits,
- MethodOffset.DepthBiasClamp))
- {
- UpdateDepthBiasState(state);
- }
-
- if (state.QueryModified(MethodOffset.StencilBackMasks,
- MethodOffset.StencilTestState,
- MethodOffset.StencilBackTestState))
- {
- UpdateStencilTestState(state);
- }
-
- // Pools.
- if (state.QueryModified(MethodOffset.SamplerPoolState, MethodOffset.SamplerIndex))
- {
- UpdateSamplerPoolState(state);
- }
-
- if (state.QueryModified(MethodOffset.TexturePoolState))
- {
- UpdateTexturePoolState(state);
- }
-
- // Rasterizer state.
- if (state.QueryModified(MethodOffset.VertexAttribState))
- {
- UpdateVertexAttribState(state);
- }
-
- if (state.QueryModified(MethodOffset.LineWidthSmooth, MethodOffset.LineSmoothEnable))
- {
- UpdateLineState(state);
- }
-
- if (state.QueryModified(MethodOffset.PointSize,
- MethodOffset.VertexProgramPointSize,
- MethodOffset.PointSpriteEnable,
- MethodOffset.PointCoordReplace))
- {
- UpdatePointState(state);
- }
-
- if (state.QueryModified(MethodOffset.PrimitiveRestartState))
- {
- UpdatePrimitiveRestartState(state);
- }
-
- if (state.QueryModified(MethodOffset.IndexBufferState))
- {
- UpdateIndexBufferState(state, firstIndex, indexCount);
- }
-
- if (state.QueryModified(MethodOffset.VertexBufferDrawState,
- MethodOffset.VertexBufferInstanced,
- MethodOffset.VertexBufferState,
- MethodOffset.VertexBufferEndAddress))
- {
- UpdateVertexBufferState(state);
- }
-
- if (state.QueryModified(MethodOffset.FaceState))
- {
- UpdateFaceState(state);
- }
-
- if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
- {
- UpdateRtColorMask(state);
- }
-
- if (state.QueryModified(MethodOffset.BlendIndependent,
- MethodOffset.BlendConstant,
- MethodOffset.BlendStateCommon,
- MethodOffset.BlendEnableCommon,
- MethodOffset.BlendEnable,
- MethodOffset.BlendState))
- {
- UpdateBlendState(state);
- }
-
- if (state.QueryModified(MethodOffset.LogicOpState))
- {
- UpdateLogicOpState(state);
- }
-
- CommitBindings(state);
-
- if (tfEnable && !_prevTfEnable)
- {
- _context.Renderer.Pipeline.BeginTransformFeedback(Topology);
- _prevTfEnable = true;
- }
- }
-
- /// <summary>
- /// Updates Rasterizer primitive discard state based on guest gpu state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateRasterizerState(GpuState state)
- {
- Boolean32 enable = state.Get<Boolean32>(MethodOffset.RasterizeEnable);
- _context.Renderer.Pipeline.SetRasterizerDiscard(!enable);
- }
-
- /// <summary>
- /// Ensures that the bindings are visible to the host GPU.
- /// Note: this actually performs the binding using the host graphics API.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void CommitBindings(GpuState state)
- {
- UpdateStorageBuffers(state);
-
- state.Channel.TextureManager.CommitGraphicsBindings();
- state.Channel.BufferManager.CommitGraphicsBindings();
- }
-
- /// <summary>
- /// Updates storage buffer bindings.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateStorageBuffers(GpuState state)
- {
- for (int stage = 0; stage < _currentProgramInfo.Length; stage++)
- {
- ShaderProgramInfo info = _currentProgramInfo[stage];
-
- if (info == null)
- {
- continue;
- }
-
- for (int index = 0; index < info.SBuffers.Count; index++)
- {
- BufferDescriptor sb = info.SBuffers[index];
-
- ulong sbDescAddress = state.Channel.BufferManager.GetGraphicsUniformBufferAddress(stage, 0);
-
- int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
-
- sbDescAddress += (ulong)sbDescOffset;
-
- SbDescriptor sbDescriptor = state.Channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
-
- state.Channel.BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
- }
- }
- }
-
- /// <summary>
- /// Updates render targets (color and depth-stencil buffers) based on current render target state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- /// <param name="useControl">Use draw buffers information from render target control register</param>
- /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
- private void UpdateRenderTargetState(GpuState state, bool useControl, int singleUse = -1)
- {
- var memoryManager = state.Channel.MemoryManager;
- var rtControl = state.Get<RtControl>(MethodOffset.RtControl);
-
- int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
-
- var msaaMode = state.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
-
- int samplesInX = msaaMode.SamplesInX();
- int samplesInY = msaaMode.SamplesInY();
-
- var scissor = state.Get<ScreenScissorState>(MethodOffset.ScreenScissorState);
- Size sizeHint = new Size(scissor.X + scissor.Width, scissor.Y + scissor.Height, 1);
-
- bool changedScale = false;
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
-
- var colorState = state.Get<RtColorState>(MethodOffset.RtColorState, rtIndex);
-
- if (index >= count || !IsRtEnabled(colorState))
- {
- changedScale |= state.Channel.TextureManager.SetRenderTargetColor(index, null);
-
- continue;
- }
-
- Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture(
- memoryManager,
- colorState,
- samplesInX,
- samplesInY,
- sizeHint);
-
- changedScale |= state.Channel.TextureManager.SetRenderTargetColor(index, color);
- }
-
- bool dsEnable = state.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
-
- Texture depthStencil = null;
-
- if (dsEnable)
- {
- var dsState = state.Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
- var dsSize = state.Get<Size3D>(MethodOffset.RtDepthStencilSize);
-
- depthStencil = memoryManager.Physical.TextureCache.FindOrCreateTexture(
- memoryManager,
- dsState,
- dsSize,
- samplesInX,
- samplesInY,
- sizeHint);
- }
-
- changedScale |= state.Channel.TextureManager.SetRenderTargetDepthStencil(depthStencil);
-
- if (changedScale)
- {
- state.Channel.TextureManager.UpdateRenderTargetScale(singleUse);
- _context.Renderer.Pipeline.SetRenderTargetScale(state.Channel.TextureManager.RenderTargetScale);
-
- UpdateViewportTransform(state);
- UpdateScissorState(state);
- }
- }
-
- /// <summary>
- /// Checks if a render target color buffer is used.
- /// </summary>
- /// <param name="colorState">Color buffer information</param>
- /// <returns>True if the specified buffer is enabled/used, false otherwise</returns>
- private static bool IsRtEnabled(RtColorState colorState)
- {
- // Colors are disabled by writing 0 to the format.
- return colorState.Format != 0 && colorState.WidthOrStride != 0;
- }
-
- /// <summary>
- /// Updates host scissor test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateScissorState(GpuState state)
- {
- for (int index = 0; index < Constants.TotalViewports; index++)
- {
- ScissorState scissor = state.Get<ScissorState>(MethodOffset.ScissorState, index);
-
- bool enable = scissor.Enable && (scissor.X1 != 0 || scissor.Y1 != 0 || scissor.X2 != 0xffff || scissor.Y2 != 0xffff);
-
- if (enable)
- {
- int x = scissor.X1;
- int y = scissor.Y1;
- int width = scissor.X2 - x;
- int height = scissor.Y2 - y;
-
- float scale = state.Channel.TextureManager.RenderTargetScale;
- if (scale != 1f)
- {
- x = (int)(x * scale);
- y = (int)(y * scale);
- width = (int)Math.Ceiling(width * scale);
- height = (int)Math.Ceiling(height * scale);
- }
-
- _context.Renderer.Pipeline.SetScissor(index, true, x, y, width, height);
- }
- else
- {
- _context.Renderer.Pipeline.SetScissor(index, false, 0, 0, 0, 0);
- }
- }
- }
-
- /// <summary>
- /// Updates host depth clamp state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateDepthClampState(GpuState state)
- {
- ViewVolumeClipControl clip = state.Get<ViewVolumeClipControl>(MethodOffset.ViewVolumeClipControl);
- _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0);
- }
-
- /// <summary>
- /// Updates host alpha test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateAlphaTestState(GpuState state)
- {
- _context.Renderer.Pipeline.SetAlphaTest(
- state.Get<Boolean32>(MethodOffset.AlphaTestEnable),
- state.Get<float>(MethodOffset.AlphaTestRef),
- state.Get<CompareOp>(MethodOffset.AlphaTestFunc));
- }
-
- /// <summary>
- /// Updates host depth test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateDepthTestState(GpuState state)
- {
- _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
- state.Get<Boolean32>(MethodOffset.DepthTestEnable),
- state.Get<Boolean32>(MethodOffset.DepthWriteEnable),
- state.Get<CompareOp>(MethodOffset.DepthTestFunc)));
- }
-
- /// <summary>
- /// Updates host viewport transform and clipping state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateViewportTransform(GpuState state)
- {
- var yControl = state.Get<YControl> (MethodOffset.YControl);
- var face = state.Get<FaceState>(MethodOffset.FaceState);
-
- UpdateFrontFace(yControl, face.FrontFace);
-
- bool flipY = yControl.HasFlag(YControl.NegateY);
-
- Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
-
- for (int index = 0; index < Constants.TotalViewports; index++)
- {
- var transform = state.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
- var extents = state.Get<ViewportExtents> (MethodOffset.ViewportExtents, index);
-
- float scaleX = MathF.Abs(transform.ScaleX);
- float scaleY = transform.ScaleY;
-
- if (flipY)
- {
- scaleY = -scaleY;
- }
-
- if (!_context.Capabilities.SupportsViewportSwizzle && transform.UnpackSwizzleY() == ViewportSwizzle.NegativeY)
- {
- scaleY = -scaleY;
- }
-
- if (index == 0)
- {
- // Try to guess the depth mode being used on the high level API
- // based on current transform.
- // It is setup like so by said APIs:
- // If depth mode is ZeroToOne:
- // TranslateZ = Near
- // ScaleZ = Far - Near
- // If depth mode is MinusOneToOne:
- // TranslateZ = (Near + Far) / 2
- // ScaleZ = (Far - Near) / 2
- // DepthNear/Far are sorted such as that Near is always less than Far.
- DepthMode depthMode = extents.DepthNear != transform.TranslateZ &&
- extents.DepthFar != transform.TranslateZ ? DepthMode.MinusOneToOne : DepthMode.ZeroToOne;
-
- _context.Renderer.Pipeline.SetDepthMode(depthMode);
- }
-
- float x = transform.TranslateX - scaleX;
- float y = transform.TranslateY - scaleY;
-
- float width = scaleX * 2;
- float height = scaleY * 2;
-
- float scale = state.Channel.TextureManager.RenderTargetScale;
- if (scale != 1f)
- {
- x *= scale;
- y *= scale;
- width *= scale;
- height *= scale;
- }
-
- RectangleF region = new RectangleF(x, y, width, height);
-
- ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
- ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
- ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
- ViewportSwizzle swizzleW = transform.UnpackSwizzleW();
-
- float depthNear = extents.DepthNear;
- float depthFar = extents.DepthFar;
-
- if (transform.ScaleZ < 0)
- {
- float temp = depthNear;
- depthNear = depthFar;
- depthFar = temp;
- }
-
- viewports[index] = new Viewport(region, swizzleX, swizzleY, swizzleZ, swizzleW, depthNear, depthFar);
- }
-
- _context.Renderer.Pipeline.SetViewports(0, viewports);
- }
-
- /// <summary>
- /// Updates host depth bias (also called polygon offset) state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateDepthBiasState(GpuState state)
- {
- var depthBias = state.Get<DepthBiasState>(MethodOffset.DepthBiasState);
-
- float factor = state.Get<float>(MethodOffset.DepthBiasFactor);
- float units = state.Get<float>(MethodOffset.DepthBiasUnits);
- float clamp = state.Get<float>(MethodOffset.DepthBiasClamp);
-
- PolygonModeMask enables;
-
- enables = (depthBias.PointEnable ? PolygonModeMask.Point : 0);
- enables |= (depthBias.LineEnable ? PolygonModeMask.Line : 0);
- enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
-
- _context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
- }
-
- /// <summary>
- /// Updates host stencil test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateStencilTestState(GpuState state)
- {
- var backMasks = state.Get<StencilBackMasks>(MethodOffset.StencilBackMasks);
- var test = state.Get<StencilTestState>(MethodOffset.StencilTestState);
- var backTest = state.Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
-
- CompareOp backFunc;
- StencilOp backSFail;
- StencilOp backDpPass;
- StencilOp backDpFail;
- int backFuncRef;
- int backFuncMask;
- int backMask;
-
- if (backTest.TwoSided)
- {
- backFunc = backTest.BackFunc;
- backSFail = backTest.BackSFail;
- backDpPass = backTest.BackDpPass;
- backDpFail = backTest.BackDpFail;
- backFuncRef = backMasks.FuncRef;
- backFuncMask = backMasks.FuncMask;
- backMask = backMasks.Mask;
- }
- else
- {
- backFunc = test.FrontFunc;
- backSFail = test.FrontSFail;
- backDpPass = test.FrontDpPass;
- backDpFail = test.FrontDpFail;
- backFuncRef = test.FrontFuncRef;
- backFuncMask = test.FrontFuncMask;
- backMask = test.FrontMask;
- }
-
- _context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
- test.Enable,
- test.FrontFunc,
- test.FrontSFail,
- test.FrontDpPass,
- test.FrontDpFail,
- test.FrontFuncRef,
- test.FrontFuncMask,
- test.FrontMask,
- backFunc,
- backSFail,
- backDpPass,
- backDpFail,
- backFuncRef,
- backFuncMask,
- backMask));
- }
-
- /// <summary>
- /// Updates current sampler pool address and size based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateSamplerPoolState(GpuState state)
- {
- var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
- var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState);
-
- var samplerIndex = state.Get<SamplerIndex>(MethodOffset.SamplerIndex);
-
- int maximumId = samplerIndex == SamplerIndex.ViaHeaderIndex
- ? texturePool.MaximumId
- : samplerPool.MaximumId;
-
- state.Channel.TextureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), maximumId, samplerIndex);
- }
-
- /// <summary>
- /// Updates current texture pool address and size based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateTexturePoolState(GpuState state)
- {
- var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
-
- state.Channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
- state.Channel.TextureManager.SetGraphicsTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
- }
-
- /// <summary>
- /// Updates host vertex attributes based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateVertexAttribState(GpuState state)
- {
- Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
-
- for (int index = 0; index < Constants.TotalVertexAttribs; index++)
- {
- var vertexAttrib = state.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
-
- if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
- {
- Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
-
- format = Format.R32G32B32A32Float;
- }
-
- vertexAttribs[index] = new VertexAttribDescriptor(
- vertexAttrib.UnpackBufferIndex(),
- vertexAttrib.UnpackOffset(),
- vertexAttrib.UnpackIsConstant(),
- format);
- }
-
- _context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
- }
-
- /// <summary>
- /// Updates host line width based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateLineState(GpuState state)
- {
- float width = state.Get<float>(MethodOffset.LineWidthSmooth);
- bool smooth = state.Get<Boolean32>(MethodOffset.LineSmoothEnable);
-
- _context.Renderer.Pipeline.SetLineParameters(width, smooth);
- }
-
- /// <summary>
- /// Updates host point size based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdatePointState(GpuState state)
- {
- float size = state.Get<float>(MethodOffset.PointSize);
- bool isProgramPointSize = state.Get<Boolean32>(MethodOffset.VertexProgramPointSize);
- bool enablePointSprite = state.Get<Boolean32>(MethodOffset.PointSpriteEnable);
-
- // TODO: Need to figure out a way to map PointCoordReplace enable bit.
- Origin origin = (state.Get<int>(MethodOffset.PointCoordReplace) & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
-
- _context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
- }
-
- /// <summary>
- /// Updates host primitive restart based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdatePrimitiveRestartState(GpuState state)
- {
- PrimitiveRestartState primitiveRestart = state.Get<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState);
-
- _context.Renderer.Pipeline.SetPrimitiveRestart(
- primitiveRestart.Enable,
- primitiveRestart.Index);
- }
-
- /// <summary>
- /// Updates host index buffer binding based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- /// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
- /// <param name="indexCount">Number of index buffer elements used on the draw</param>
- private void UpdateIndexBufferState(GpuState state, int firstIndex, int indexCount)
- {
- var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
-
- if (indexCount == 0)
- {
- return;
- }
-
- ulong gpuVa = indexBuffer.Address.Pack();
-
- // Do not use the end address to calculate the size, because
- // the result may be much larger than the real size of the index buffer.
- ulong size = (ulong)(firstIndex + indexCount);
-
- switch (indexBuffer.Type)
- {
- case IndexType.UShort: size *= 2; break;
- case IndexType.UInt: size *= 4; break;
- }
-
- state.Channel.BufferManager.SetIndexBuffer(gpuVa, size, indexBuffer.Type);
-
- // The index buffer affects the vertex buffer size calculation, we
- // need to ensure that they are updated.
- UpdateVertexBufferState(state);
- }
-
- /// <summary>
- /// Updates host vertex buffer bindings based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateVertexBufferState(GpuState state)
- {
- _isAnyVbInstanced = false;
-
- for (int index = 0; index < Constants.TotalVertexBuffers; index++)
- {
- var vertexBuffer = state.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
-
- if (!vertexBuffer.UnpackEnable())
- {
- state.Channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
-
- continue;
- }
-
- GpuVa endAddress = state.Get<GpuVa>(MethodOffset.VertexBufferEndAddress, index);
-
- ulong address = vertexBuffer.Address.Pack();
-
- int stride = vertexBuffer.UnpackStride();
-
- bool instanced = state.Get<Boolean32>(MethodOffset.VertexBufferInstanced + index);
-
- int divisor = instanced ? vertexBuffer.Divisor : 0;
-
- _isAnyVbInstanced |= divisor != 0;
-
- ulong size;
-
- if (_ibStreamer.HasInlineIndexData || _drawIndexed || stride == 0 || instanced)
- {
- // This size may be (much) larger than the real vertex buffer size.
- // Avoid calculating it this way, unless we don't have any other option.
- size = endAddress.Pack() - address + 1;
- }
- else
- {
- // For non-indexed draws, we can guess the size from the vertex count
- // and stride.
- int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
-
- var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
-
- size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
- }
-
- state.Channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
- }
- }
-
- /// <summary>
- /// Updates host face culling and orientation based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateFaceState(GpuState state)
- {
- var yControl = state.Get<YControl> (MethodOffset.YControl);
- var face = state.Get<FaceState>(MethodOffset.FaceState);
-
- _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
-
- UpdateFrontFace(yControl, face.FrontFace);
- }
-
- /// <summary>
- /// Updates the front face based on the current front face and the origin.
- /// </summary>
- /// <param name="yControl">Y control register value, where the origin is located</param>
- /// <param name="frontFace">Front face</param>
- private void UpdateFrontFace(YControl yControl, FrontFace frontFace)
- {
- bool isUpperLeftOrigin = !yControl.HasFlag(YControl.TriangleRastFlip);
-
- if (isUpperLeftOrigin)
- {
- frontFace = frontFace == FrontFace.CounterClockwise ? FrontFace.Clockwise : FrontFace.CounterClockwise;
- }
-
- _context.Renderer.Pipeline.SetFrontFace(frontFace);
- }
-
- /// <summary>
- /// Updates host render target color masks, based on guest GPU state.
- /// This defines which color channels are written to each color buffer.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateRtColorMask(GpuState state)
- {
- bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared);
-
- Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- var colorMask = state.Get<RtColorMask>(MethodOffset.RtColorMask, rtColorMaskShared ? 0 : index);
-
- uint componentMask;
-
- componentMask = (colorMask.UnpackRed() ? 1u : 0u);
- componentMask |= (colorMask.UnpackGreen() ? 2u : 0u);
- componentMask |= (colorMask.UnpackBlue() ? 4u : 0u);
- componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
-
- componentMasks[index] = componentMask;
- }
-
- _context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
- }
-
- /// <summary>
- /// Updates host render target color buffer blending state, based on guest state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateBlendState(GpuState state)
- {
- bool blendIndependent = state.Get<Boolean32>(MethodOffset.BlendIndependent);
- ColorF blendConstant = state.Get<ColorF>(MethodOffset.BlendConstant);
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- BlendDescriptor descriptor;
-
- if (blendIndependent)
- {
- bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, index);
- var blend = state.Get<BlendState>(MethodOffset.BlendState, index);
-
- descriptor = new BlendDescriptor(
- enable,
- blendConstant,
- blend.ColorOp,
- blend.ColorSrcFactor,
- blend.ColorDstFactor,
- blend.AlphaOp,
- blend.AlphaSrcFactor,
- blend.AlphaDstFactor);
- }
- else
- {
- bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, 0);
- var blend = state.Get<BlendStateCommon>(MethodOffset.BlendStateCommon);
-
- descriptor = new BlendDescriptor(
- enable,
- blendConstant,
- blend.ColorOp,
- blend.ColorSrcFactor,
- blend.ColorDstFactor,
- blend.AlphaOp,
- blend.AlphaSrcFactor,
- blend.AlphaDstFactor);
- }
-
- _context.Renderer.Pipeline.SetBlendState(index, descriptor);
- }
- }
-
- /// <summary>
- /// Updates host logical operation state, based on guest state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- public void UpdateLogicOpState(GpuState state)
- {
- LogicalOpState logicOpState = state.Get<LogicalOpState>(MethodOffset.LogicOpState);
-
- _context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
- }
-
- /// <summary>
- /// Updates host shaders based on the guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateShaderState(GpuState state)
- {
- ShaderAddresses addresses = new ShaderAddresses();
-
- Span<ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);
-
- Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
-
- ulong baseAddress = state.Get<GpuVa>(MethodOffset.ShaderBaseAddress).Pack();
-
- for (int index = 0; index < 6; index++)
- {
- var shader = state.Get<ShaderState>(MethodOffset.ShaderState, index);
-
- if (!shader.UnpackEnable() && index != 1)
- {
- continue;
- }
-
- addressesArray[index] = baseAddress + shader.Offset;
- }
-
- ShaderBundle gs = state.Channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(state, addresses);
-
- byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
-
- _vsUsesInstanceId = gs.Shaders[0]?.Info.UsesInstanceId ?? false;
- _vsClipDistancesWritten = gs.Shaders[0]?.Info.ClipDistancesWritten ?? 0;
-
- if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
- {
- UpdateUserClipState(state);
- }
-
- int storageBufferBindingsCount = 0;
- int uniformBufferBindingsCount = 0;
-
- for (int stage = 0; stage < Constants.ShaderStages; stage++)
- {
- ShaderProgramInfo info = gs.Shaders[stage]?.Info;
-
- _currentProgramInfo[stage] = info;
-
- if (info == null)
- {
- state.Channel.TextureManager.SetGraphicsTextures(stage, Array.Empty<TextureBindingInfo>());
- state.Channel.TextureManager.SetGraphicsImages(stage, Array.Empty<TextureBindingInfo>());
- state.Channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
- state.Channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
- continue;
- }
-
- 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);
- }
-
- state.Channel.TextureManager.SetGraphicsTextures(stage, 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);
- }
-
- state.Channel.TextureManager.SetGraphicsImages(stage, imageBindings);
-
- state.Channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
- state.Channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
-
- if (info.SBuffers.Count != 0)
- {
- storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
- }
-
- if (info.CBuffers.Count != 0)
- {
- uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
- }
- }
-
- state.Channel.BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
- state.Channel.BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);
-
- _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
- }
-
- /// <summary>
- /// Forces the shaders to be rebound on the next draw.
- /// </summary>
- public void ForceShaderUpdate()
- {
- _forceShaderUpdate = true;
- }
-
- /// <summary>
- /// Updates transform feedback buffer state based on the guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateTfBufferState(GpuState state)
- {
- for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
- {
- TfBufferState tfb = state.Get<TfBufferState>(MethodOffset.TfBufferState, index);
-
- if (!tfb.Enable)
- {
- state.Channel.BufferManager.SetTransformFeedbackBuffer(index, 0, 0);
-
- continue;
- }
-
- state.Channel.BufferManager.SetTransformFeedbackBuffer(index, tfb.Address.Pack(), (uint)tfb.Size);
- }
- }
-
- /// <summary>
- /// Updates user-defined clipping based on the guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateUserClipState(GpuState state)
- {
- int clipMask = state.Get<int>(MethodOffset.ClipDistanceEnable) & _vsClipDistancesWritten;
-
- for (int i = 0; i < Constants.TotalClipDistances; ++i)
- {
- _context.Renderer.Pipeline.SetUserClipDistance(i, (clipMask & (1 << i)) != 0);
- }
- }
-
- /// <summary>
- /// Issues a texture barrier.
- /// This waits until previous texture writes from the GPU to finish, before
- /// performing new operations with said textures.
- /// </summary>
- /// <param name="state">Current GPU state (unused)</param>
- /// <param name="argument">Method call argument (unused)</param>
- private void TextureBarrier(GpuState state, int argument)
- {
- _context.Renderer.Pipeline.TextureBarrier();
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- /// <param name="state">Current GPU state (unused)</param>
- /// <param name="argument">Method call argument (unused)</param>
- private void TextureBarrierTiled(GpuState state, int argument)
- {
- _context.Renderer.Pipeline.TextureBarrierTiled();
- }
- }
-} \ No newline at end of file