Add per-source type memory change tracking, simplified state change tracking, other fixes

This commit is contained in:
gdk 2019-10-26 14:50:52 -03:00 committed by Thog
parent 1b7d955195
commit 8cba252b23
40 changed files with 494 additions and 668 deletions

View File

@ -14,8 +14,6 @@ namespace ARMeilleure.Memory
public const int PageSize = 1 << PageBits;
public const int PageMask = PageSize - 1;
private const long PteFlagNotModified = 1;
internal const long PteFlagsMask = 7;
public IntPtr Ram { get; private set; }
@ -106,6 +104,11 @@ namespace ARMeilleure.Memory
ptr = (byte*)ptrUlong;
}
if (ptr == null)
{
return IntPtr.Zero;
}
return new IntPtr(ptr + (position & PageMask));
}
@ -122,10 +125,7 @@ namespace ARMeilleure.Memory
if ((ptrUlong & PteFlagsMask) != 0)
{
if ((ptrUlong & PteFlagNotModified) != 0)
{
ClearPtEntryFlag(position, PteFlagNotModified);
}
ClearPtEntryFlag(position, PteFlagsMask);
ptrUlong &= ~(ulong)PteFlagsMask;
@ -253,8 +253,10 @@ namespace ARMeilleure.Memory
return ptePtr;
}
public unsafe (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size)
public unsafe (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, int id)
{
ulong idMask = 1UL << id;
List<(ulong, ulong)> ranges = new List<(ulong, ulong)>();
ulong endAddress = (address + size + PageMask) & ~(ulong)PageMask;
@ -272,12 +274,12 @@ namespace ARMeilleure.Memory
ulong ptrUlong = (ulong)ptr;
if ((ptrUlong & PteFlagNotModified) == 0)
if ((ptrUlong & idMask) == 0)
{
// Modified.
currSize += PageSize;
SetPtEntryFlag((long)address, PteFlagNotModified);
SetPtEntryFlag((long)address, (long)idMask);
}
else
{

View File

@ -27,15 +27,15 @@ namespace Ryujinx.Graphics.Gpu.Engine
_context.Renderer.Pipeline.BindProgram(cs.Interface);
PoolState samplerPool = _context.State.GetSamplerPoolState();
var samplerPool = _context.State.Get<PoolState>(MethodOffset.SamplerPoolState);
_textureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId);
PoolState texturePool = _context.State.GetTexturePoolState();
var texturePool = _context.State.Get<PoolState>(MethodOffset.TexturePoolState);
_textureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
_textureManager.SetComputeTextureBufferIndex(_context.State.GetTextureBufferIndex());
_textureManager.SetComputeTextureBufferIndex(_context.State.Get<int>(MethodOffset.TextureBufferIndex));
ShaderProgramInfo info = cs.Shader.Info;
@ -117,6 +117,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
dispatchParams.UnpackGridSizeX(),
dispatchParams.UnpackGridSizeY(),
dispatchParams.UnpackGridSizeZ());
UpdateShaderState();
}
}
}

View File

@ -12,9 +12,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
private int _offset;
private int _size;
public void Execute(int argument)
public void LaunchDma(int argument)
{
_params = _context.State.Get<Inline2MemoryParams>(MethodOffset.Inline2MemoryParams);
_params = _context.State.Get<Inline2MemoryParams>(MethodOffset.I2mParams);
_isLinear = (argument & 1) != 0;
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
_size = _params.LineLengthIn * _params.LineCount;
}
public void PushData(int argument)
public void LoadInlineData(int argument)
{
if (_isLinear)
{

View File

@ -7,7 +7,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
private void Clear(int argument)
{
UpdateState();
UpdateRenderTargetStateIfNeeded();
_textureManager.CommitGraphicsBindings();
bool clearDepth = (argument & 1) != 0;
bool clearStencil = (argument & 2) != 0;
@ -18,7 +20,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (componentMask != 0)
{
ClearColors clearColor = _context.State.GetClearColors();
var clearColor = _context.State.Get<ClearColors>(MethodOffset.ClearColors);
ColorF color = new ColorF(
clearColor.Red,
@ -26,22 +28,19 @@ namespace Ryujinx.Graphics.Gpu.Engine
clearColor.Blue,
clearColor.Alpha);
_context.Renderer.Pipeline.ClearRenderTargetColor(
index,
componentMask,
color);
_context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
}
if (clearDepth || clearStencil)
{
float depthValue = _context.State.GetClearDepthValue();
int stencilValue = _context.State.GetClearStencilValue();
float depthValue = _context.State.Get<float>(MethodOffset.ClearDepthValue);
int stencilValue = _context.State.Get<int> (MethodOffset.ClearStencilValue);
int stencilMask = 0;
if (clearStencil)
{
stencilMask = _context.State.GetStencilTestState().FrontMask;
stencilMask = _context.State.Get<StencilTestState>(MethodOffset.StencilTestState).FrontMask;
}
_context.Renderer.Pipeline.ClearRenderTargetDepthStencil(

View File

@ -7,8 +7,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
private void CopyTexture(int argument)
{
CopyTexture dstCopyTexture = _context.State.GetCopyDstTexture();
CopyTexture srcCopyTexture = _context.State.GetCopySrcTexture();
var dstCopyTexture = _context.State.Get<CopyTexture>(MethodOffset.CopyDstTexture);
var srcCopyTexture = _context.State.Get<CopyTexture>(MethodOffset.CopySrcTexture);
Image.Texture srcTexture = _textureManager.FindOrCreateTexture(srcCopyTexture);
@ -32,9 +32,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
return;
}
CopyTextureControl control = _context.State.GetCopyTextureControl();
var control = _context.State.Get<CopyTextureControl>(MethodOffset.CopyTextureControl);
CopyRegion region = _context.State.GetCopyRegion();
var region = _context.State.Get<CopyRegion>(MethodOffset.CopyRegion);
int srcX1 = (int)(region.SrcXF >> 32);
int srcY1 = (int)(region.SrcYF >> 32);

View File

@ -39,12 +39,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
_instancedIndexed = _drawIndexed;
_instancedFirstIndex = _firstIndex;
_instancedFirstVertex = _context.State.GetBaseVertex();
_instancedFirstInstance = _context.State.GetBaseInstance();
_instancedFirstVertex = _context.State.Get<int>(MethodOffset.FirstVertex);
_instancedFirstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
_instancedIndexCount = _indexCount;
VertexBufferDrawState drawState = _context.State.GetVertexBufferDrawState();
var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
_instancedDrawStateFirst = drawState.First;
_instancedDrawStateCount = drawState.Count;
@ -53,13 +53,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
return;
}
int firstInstance = _context.State.GetBaseInstance();
int firstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
if (_drawIndexed)
{
_drawIndexed = false;
int firstVertex = _context.State.GetBaseVertex();
int firstVertex = _context.State.Get<int>(MethodOffset.FirstVertex);
_context.Renderer.Pipeline.DrawIndexed(
_indexCount,
@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
else
{
VertexBufferDrawState drawState = _context.State.GetVertexBufferDrawState();
var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
_context.Renderer.Pipeline.Draw(
drawState.Count,
@ -98,7 +98,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
}
private void SetIndexCount(int argument)
private void SetIndexBufferCount(int argument)
{
_drawIndexed = true;
}

View File

@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void ReportSemaphore()
{
ReportState state = _context.State.GetReportState();
var state = _context.State.Get<ReportState>(MethodOffset.ReportState);
_context.MemoryAccessor.Write(state.Address.Pack(), state.Payload);
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
Span<byte> data = MemoryMarshal.Cast<CounterData, byte>(counterDataSpan);
ReportState state = _context.State.GetReportState();
var state = _context.State.Get<ReportState>(MethodOffset.ReportState);
_context.MemoryAccessor.Write(state.Address.Pack(), data);
}

View File

@ -4,27 +4,27 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
partial class Methods
{
private void UniformBufferBind0(int argument)
private void UniformBufferBindVertex(int argument)
{
UniformBufferBind(argument, ShaderType.Vertex);
}
private void UniformBufferBind1(int argument)
private void UniformBufferBindTessControl(int argument)
{
UniformBufferBind(argument, ShaderType.TessellationControl);
}
private void UniformBufferBind2(int argument)
private void UniformBufferBindTessEvaluation(int argument)
{
UniformBufferBind(argument, ShaderType.TessellationEvaluation);
}
private void UniformBufferBind3(int argument)
private void UniformBufferBindGeometry(int argument)
{
UniformBufferBind(argument, ShaderType.Geometry);
}
private void UniformBufferBind4(int argument)
private void UniformBufferBindFragment(int argument)
{
UniformBufferBind(argument, ShaderType.Fragment);
}
@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
if (enable)
{
UniformBufferState uniformBuffer = _context.State.GetUniformBufferState();
var uniformBuffer = _context.State.Get<UniformBufferState>(MethodOffset.UniformBufferState);
ulong address = uniformBuffer.Address.Pack();

View File

@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
private void UniformBufferUpdate(int argument)
{
UniformBufferState uniformBuffer = _context.State.GetUniformBufferState();
var uniformBuffer = _context.State.Get<UniformBufferState>(MethodOffset.UniformBufferState);
_context.MemoryAccessor.Write(uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset, argument);

View File

@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
private ShaderCache _shaderCache;
private ShaderProgramInfo[] _currentProgramInfo;
private BufferManager _bufferManager;
private TextureManager _textureManager;
@ -33,6 +35,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
_shaderCache = new ShaderCache(_context);
_currentProgramInfo = new ShaderProgramInfo[Constants.TotalShaderStages];
_bufferManager = new BufferManager(context);
_textureManager = new TextureManager(context);
@ -41,128 +45,184 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void RegisterCallbacks()
{
_context.State.RegisterCopyBufferCallback(CopyBuffer);
_context.State.RegisterCopyTextureCallback(CopyTexture);
_context.State.RegisterCallback(MethodOffset.LaunchDma, LaunchDma);
_context.State.RegisterCallback(MethodOffset.LoadInlineData, LoadInlineData);
_context.State.RegisterDrawEndCallback(DrawEnd);
_context.State.RegisterCallback(MethodOffset.Dispatch, Dispatch);
_context.State.RegisterDrawBeginCallback(DrawBegin);
_context.State.RegisterSetIndexCountCallback(SetIndexCount);
_context.State.RegisterClearCallback(Clear);
_context.State.RegisterReportCallback(Report);
_context.State.RegisterUniformBufferUpdateCallback(UniformBufferUpdate);
_context.State.RegisterUniformBufferBind0Callback(UniformBufferBind0);
_context.State.RegisterUniformBufferBind1Callback(UniformBufferBind1);
_context.State.RegisterUniformBufferBind2Callback(UniformBufferBind2);
_context.State.RegisterUniformBufferBind3Callback(UniformBufferBind3);
_context.State.RegisterUniformBufferBind4Callback(UniformBufferBind4);
_context.State.RegisterCallback(MethodOffset.CopyBuffer, CopyBuffer);
_context.State.RegisterCallback(MethodOffset.CopyTexture, CopyTexture);
_context.State.RegisterCallback(MethodOffset.TextureBarrier, TextureBarrier);
_context.State.RegisterCallback(MethodOffset.InvalidateTextures, InvalidateTextures);
_context.State.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
_context.State.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
_context.State.RegisterCallback(MethodOffset.Inline2MemoryExecute, Execute);
_context.State.RegisterCallback(MethodOffset.Inline2MemoryPushData, PushData);
_context.State.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
_context.State.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
_context.State.RegisterCallback(MethodOffset.Dispatch, Dispatch);
_context.State.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
_context.State.RegisterCallback(MethodOffset.Clear, Clear);
_context.State.RegisterCallback(MethodOffset.Report, Report);
_context.State.RegisterCallback(MethodOffset.UniformBufferUpdateData, 16, UniformBufferUpdate);
_context.State.RegisterCallback(MethodOffset.UniformBufferBindVertex, UniformBufferBindVertex);
_context.State.RegisterCallback(MethodOffset.UniformBufferBindTessControl, UniformBufferBindTessControl);
_context.State.RegisterCallback(MethodOffset.UniformBufferBindTessEvaluation, UniformBufferBindTessEvaluation);
_context.State.RegisterCallback(MethodOffset.UniformBufferBindGeometry, UniformBufferBindGeometry);
_context.State.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment);
}
public Image.Texture GetTexture(ulong address) => _textureManager.Find2(address);
private void UpdateState()
{
if ((_context.State.StateWriteFlags & StateWriteFlags.Any) == 0)
{
CommitBindings();
return;
}
// 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 ((_context.State.StateWriteFlags & StateWriteFlags.ShaderState) != 0)
if (_context.State.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState))
{
UpdateShaderState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.RenderTargetGroup) != 0)
{
UpdateRenderTargetGroupState();
}
UpdateRenderTargetStateIfNeeded();
if ((_context.State.StateWriteFlags & StateWriteFlags.DepthTestState) != 0)
if (_context.State.QueryModified(MethodOffset.DepthTestEnable,
MethodOffset.DepthWriteEnable,
MethodOffset.DepthTestFunc))
{
UpdateDepthTestState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.ViewportTransform) != 0)
if (_context.State.QueryModified(MethodOffset.ViewportTransform, MethodOffset.ViewportExtents))
{
UpdateViewportTransform();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.DepthBiasState) != 0)
if (_context.State.QueryModified(MethodOffset.DepthBiasState,
MethodOffset.DepthBiasFactor,
MethodOffset.DepthBiasUnits,
MethodOffset.DepthBiasClamp))
{
UpdateDepthBiasState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.StencilTestState) != 0)
if (_context.State.QueryModified(MethodOffset.StencilBackMasks,
MethodOffset.StencilTestState,
MethodOffset.StencilBackTestState))
{
UpdateStencilTestState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.SamplerPoolState) != 0)
// Pools.
if (_context.State.QueryModified(MethodOffset.SamplerPoolState))
{
UpdateSamplerPoolState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.TexturePoolState) != 0)
if (_context.State.QueryModified(MethodOffset.TexturePoolState))
{
UpdateTexturePoolState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.InputAssemblerGroup) != 0)
// Input assembler state.
if (_context.State.QueryModified(MethodOffset.VertexAttribState))
{
UpdateInputAssemblerGroupState();
UpdateVertexAttribState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.FaceState) != 0)
if (_context.State.QueryModified(MethodOffset.PrimitiveRestartState))
{
UpdatePrimitiveRestartState();
}
if (_context.State.QueryModified(MethodOffset.IndexBufferState))
{
UpdateIndexBufferState();
}
if (_context.State.QueryModified(MethodOffset.VertexBufferDrawState,
MethodOffset.VertexBufferInstanced,
MethodOffset.VertexBufferState,
MethodOffset.VertexBufferEndAddress))
{
UpdateVertexBufferState();
}
if (_context.State.QueryModified(MethodOffset.FaceState))
{
UpdateFaceState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.RtColorMask) != 0)
if (_context.State.QueryModified(MethodOffset.RtColorMask))
{
UpdateRtColorMask();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.BlendState) != 0)
if (_context.State.QueryModified(MethodOffset.BlendEnable, MethodOffset.BlendState))
{
UpdateBlendState();
}
_context.State.StateWriteFlags &= ~StateWriteFlags.Any;
CommitBindings();
}
private void CommitBindings()
{
UpdateStorageBuffers();
_bufferManager.CommitBindings();
_textureManager.CommitGraphicsBindings();
}
private void UpdateRenderTargetGroupState()
private void UpdateStorageBuffers()
{
TextureMsaaMode msaaMode = _context.State.GetRtMsaaMode();
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 = _bufferManager.GetGraphicsUniformBufferAddress(stage, 0);
int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
sbDescAddress += (ulong)sbDescOffset;
Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
_bufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
}
}
}
private void UpdateRenderTargetStateIfNeeded()
{
if (_context.State.QueryModified(MethodOffset.RtColorState,
MethodOffset.RtDepthStencilState,
MethodOffset.RtDepthStencilSize,
MethodOffset.RtDepthStencilEnable))
{
UpdateRenderTargetState();
}
}
private void UpdateRenderTargetState()
{
var msaaMode = _context.State.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
int samplesInX = msaaMode.SamplesInX();
int samplesInY = msaaMode.SamplesInY();
@ -173,7 +233,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
RtColorState colorState = _context.State.GetRtColorState(index);
var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
if (!IsRtEnabled(colorState))
{
@ -189,7 +249,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
_textureManager.SetRenderTargetColor(index, color);
color.Modified = true;
if (color != null)
{
color.Modified = true;
}
}
}
else
@ -199,14 +262,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
color3D.Modified = true;
}
bool dsEnable = _context.State.Get<bool>(MethodOffset.RtDepthStencilEnable);
bool dsEnable = _context.State.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
Image.Texture depthStencil = null;
if (dsEnable)
{
var dsState = _context.State.GetRtDepthStencilState();
var dsSize = _context.State.GetRtDepthStencilSize();
var dsState = _context.State.Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
var dsSize = _context.State.Get<Size3D> (MethodOffset.RtDepthStencilSize);
depthStencil = _textureManager.FindOrCreateTexture(
dsState,
@ -216,11 +279,16 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
_textureManager.SetRenderTargetDepthStencil(depthStencil);
if (depthStencil != null)
{
depthStencil.Modified = true;
}
}
private Image.Texture Get3DRenderTarget(int samplesInX, int samplesInY)
{
RtColorState colorState0 = _context.State.GetRtColorState(0);
var colorState0 = _context.State.Get<RtColorState>(MethodOffset.RtColorState, 0);
if (!IsRtEnabled(colorState0) || !colorState0.MemoryLayout.UnpackIsTarget3D() || colorState0.Depth != 1)
{
@ -232,7 +300,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 1; index < Constants.TotalRenderTargets; index++)
{
RtColorState colorState = _context.State.GetRtColorState(index);
var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
if (!IsRtEnabled(colorState))
{
@ -266,9 +334,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateDepthTestState()
{
_context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
_context.State.GetDepthTestEnable().IsTrue(),
_context.State.GetDepthWriteEnable().IsTrue(),
_context.State.GetDepthTestFunc()));
_context.State.Get<Boolean32>(MethodOffset.DepthTestEnable),
_context.State.Get<Boolean32>(MethodOffset.DepthWriteEnable),
_context.State.Get<CompareOp>(MethodOffset.DepthTestFunc)));
}
private void UpdateViewportTransform()
@ -277,8 +345,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 0; index < Constants.TotalViewports; index++)
{
var transform = _context.State.Get<ViewportTransform>(MethodOffset.ViewportTransform + index * 8);
var extents = _context.State.Get<ViewportExtents> (MethodOffset.ViewportExtents + index * 4);
var transform = _context.State.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
var extents = _context.State.Get<ViewportExtents> (MethodOffset.ViewportExtents, index);
float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
@ -303,7 +371,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateDepthBiasState()
{
var polygonOffset = _context.State.Get<DepthBiasState>(MethodOffset.DepthBiasState);
var depthBias = _context.State.Get<DepthBiasState>(MethodOffset.DepthBiasState);
float factor = _context.State.Get<float>(MethodOffset.DepthBiasFactor);
float units = _context.State.Get<float>(MethodOffset.DepthBiasUnits);
@ -311,18 +379,18 @@ namespace Ryujinx.Graphics.Gpu.Engine
PolygonModeMask enables = 0;
enables = (polygonOffset.PointEnable.IsTrue() ? PolygonModeMask.Point : 0);
enables |= (polygonOffset.LineEnable.IsTrue() ? PolygonModeMask.Line : 0);
enables |= (polygonOffset.FillEnable.IsTrue() ? PolygonModeMask.Fill : 0);
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, clamp);
}
private void UpdateStencilTestState()
{
StencilBackMasks backMasks = _context.State.GetStencilBackMasks();
StencilTestState test = _context.State.GetStencilTestState();
StencilBackTestState backTest = _context.State.GetStencilBackTestState();
var backMasks = _context.State.Get<StencilBackMasks> (MethodOffset.StencilBackMasks);
var test = _context.State.Get<StencilTestState> (MethodOffset.StencilTestState);
var backTest = _context.State.Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
CompareOp backFunc;
StencilOp backSFail;
@ -332,7 +400,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
int backFuncMask;
int backMask;
if (backTest.TwoSided.IsTrue())
if (backTest.TwoSided)
{
backFunc = backTest.BackFunc;
backSFail = backTest.BackSFail;
@ -354,7 +422,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
}
_context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
test.Enable.IsTrue(),
test.Enable,
test.FrontFunc,
test.FrontSFail,
test.FrontDpPass,
@ -373,42 +441,18 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateSamplerPoolState()
{
PoolState samplerPool = _context.State.GetSamplerPoolState();
var samplerPool = _context.State.Get<PoolState>(MethodOffset.SamplerPoolState);
_textureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId);
}
private void UpdateTexturePoolState()
{
PoolState texturePool = _context.State.GetTexturePoolState();
var texturePool = _context.State.Get<PoolState>(MethodOffset.TexturePoolState);
_textureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
_textureManager.SetGraphicsTextureBufferIndex(_context.State.GetTextureBufferIndex());
}
private void UpdateInputAssemblerGroupState()
{
// Must be updated before the vertex buffer.
if ((_context.State.StateWriteFlags & StateWriteFlags.VertexAttribState) != 0)
{
UpdateVertexAttribState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.PrimitiveRestartState) != 0)
{
UpdatePrimitiveRestartState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.IndexBufferState) != 0)
{
UpdateIndexBufferState();
}
if ((_context.State.StateWriteFlags & StateWriteFlags.VertexBufferState) != 0)
{
UpdateVertexBufferState();
}
_textureManager.SetGraphicsTextureBufferIndex(_context.State.Get<int>(MethodOffset.TextureBufferIndex));
}
private void UpdateVertexAttribState()
@ -417,7 +461,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 0; index < 16; index++)
{
VertexAttribState vertexAttrib = _context.State.GetVertexAttribState(index);
var vertexAttrib = _context.State.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
{
@ -446,7 +490,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateIndexBufferState()
{
IndexBufferState indexBuffer = _context.State.GetIndexBufferState();
var indexBuffer = _context.State.Get<IndexBufferState>(MethodOffset.IndexBufferState);
_firstIndex = indexBuffer.First;
_indexCount = indexBuffer.Count;
@ -475,70 +519,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
UpdateVertexBufferState();
}
private uint GetIndexBufferMaxIndex(ulong gpuVa, ulong size, IndexType type)
{
ulong address = _context.MemoryManager.Translate(gpuVa);
Span<byte> data = _context.PhysicalMemory.Read(address, size);
uint maxIndex = 0;
switch (type)
{
case IndexType.UByte:
{
for (int index = 0; index < data.Length; index++)
{
if (maxIndex < data[index])
{
maxIndex = data[index];
}
}
break;
}
case IndexType.UShort:
{
Span<ushort> indices = MemoryMarshal.Cast<byte, ushort>(data);
for (int index = 0; index < indices.Length; index++)
{
if (maxIndex < indices[index])
{
maxIndex = indices[index];
}
}
break;
}
case IndexType.UInt:
{
Span<uint> indices = MemoryMarshal.Cast<byte, uint>(data);
for (int index = 0; index < indices.Length; index++)
{
if (maxIndex < indices[index])
{
maxIndex = indices[index];
}
}
break;
}
}
return maxIndex;
}
private void UpdateVertexBufferState()
{
_isAnyVbInstanced = false;
for (int index = 0; index < 16; index++)
{
VertexBufferState vertexBuffer = _context.State.GetVertexBufferState(index);
var vertexBuffer = _context.State.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
if (!vertexBuffer.UnpackEnable())
{
@ -547,13 +534,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
continue;
}
GpuVa endAddress = _context.State.GetVertexBufferEndAddress(index);
GpuVa endAddress = _context.State.Get<GpuVa>(MethodOffset.VertexBufferEndAddress, index);
ulong address = vertexBuffer.Address.Pack();
int stride = vertexBuffer.UnpackStride();
bool instanced = _context.State.Get<bool>(MethodOffset.VertexBufferInstanced + index);
bool instanced = _context.State.Get<Boolean32>(MethodOffset.VertexBufferInstanced + index);
int divisor = instanced ? vertexBuffer.Divisor : 0;
@ -571,9 +558,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
// For non-indexed draws, we can guess the size from the vertex count
// and stride.
int firstInstance = _context.State.GetBaseInstance();
int firstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
VertexBufferDrawState drawState = _context.State.GetVertexBufferDrawState();
var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
}
@ -584,9 +571,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
private void UpdateFaceState()
{
FaceState face = _context.State.GetFaceState();
var face = _context.State.Get<FaceState>(MethodOffset.FaceState);
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable.IsTrue(), face.CullFace);
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
_context.Renderer.Pipeline.SetFrontFace(face.FrontFace);
}
@ -597,7 +584,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
RtColorMask colorMask = _context.State.Get<RtColorMask>(MethodOffset.RtColorMask + index);
var colorMask = _context.State.Get<RtColorMask>(MethodOffset.RtColorMask, index);
uint componentMask = 0;
@ -618,12 +605,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 0; index < 8; index++)
{
bool blendEnable = _context.State.GetBlendEnable(index).IsTrue();
bool enable = _context.State.Get<Boolean32>(MethodOffset.BlendEnable, index);
BlendState blend = _context.State.GetBlendState(index);
var blend = _context.State.Get<BlendState>(MethodOffset.BlendState, index);
BlendDescriptor descriptor = new BlendDescriptor(
blendEnable,
enable,
blend.ColorOp,
blend.ColorSrcFactor,
blend.ColorDstFactor,
@ -656,11 +643,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
ulong baseAddress = _context.State.GetShaderBaseAddress().Pack();
ulong baseAddress = _context.State.Get<GpuVa>(MethodOffset.ShaderBaseAddress).Pack();
for (int index = 0; index < 6; index++)
{
ShaderState shader = _context.State.GetShaderState(index);
var shader = _context.State.Get<ShaderState>(MethodOffset.ShaderState, index);
if (!shader.UnpackEnable() && index != 1)
{
@ -678,6 +665,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
{
ShaderProgramInfo info = gs.Shader[stage]?.Info;
_currentProgramInfo[stage] = info;
if (info == null)
{
continue;
@ -714,21 +703,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
for (int index = 0; index < info.SBuffers.Count; index++)
{
BufferDescriptor sb = info.SBuffers[index];
sbEnableMask |= 1u << sb.Slot;
ulong sbDescAddress = _bufferManager.GetGraphicsUniformBufferAddress(stage, 0);
int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
sbDescAddress += (ulong)sbDescOffset;
Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
_bufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
sbEnableMask |= 1u << info.SBuffers[index].Slot;
}
for (int index = 0; index < info.CBuffers.Count; index++)

View File

@ -1,3 +1,4 @@
using Ryujinx.Graphics.Gpu.Memory;
using System;
namespace Ryujinx.Graphics.Gpu.Image
@ -31,7 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public void SynchronizeMemory()
{
(ulong, ulong)[] modifiedRanges = Context.PhysicalMemory.GetModifiedRanges(Address, Size);
(ulong, ulong)[] modifiedRanges = Context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.TexturePool);
for (int index = 0; index < modifiedRanges.Length; index++)
{

View File

@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_sequenceNumber = _context.SequenceNumber;
bool modified = _context.PhysicalMemory.GetModifiedRanges(Address, Size).Length != 0;
bool modified = _context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.Texture).Length != 0;
if (!modified && _hasData)
{

View File

@ -114,7 +114,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public void CommitComputeBindings()
{
// Evert time we switch between graphics and compute work,
// Every time we switch between graphics and compute work,
// we must rebind everything.
// Since compute work happens less often, we always do that
// before and after the compute dispatch.

View File

@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
return;
}
(ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size);
(ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size, ResourceName.Buffer);
for (int index = 0; index < modifiedRanges.Length; index++)
{

View File

@ -116,9 +116,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
ulong address = TranslateAndCreateBuffer(gpuVa, size);
_gpStorageBuffers[stage].Bind(index, address, size);
if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
_gpStorageBuffers[stage].Buffers[index].Size != size)
{
_gpStorageBuffersDirty = true;
}
_gpStorageBuffersDirty = true;
_gpStorageBuffers[stage].Bind(index, address, size);
}
public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)

View File

@ -10,6 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
void Write(ulong address, Span<byte> data);
(ulong, ulong)[] GetModifiedRanges(ulong address, ulong size);
(ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, ResourceName name);
}
}

View File

@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
private const int PtLvl0Bits = 14;
private const int PtLvl1Bits = 14;
private const int PtPageBits = 12;
public const int PtPageBits = 12;
private const ulong PtLvl0Size = 1UL << PtLvl0Bits;
private const ulong PtLvl1Size = 1UL << PtLvl1Bits;

View File

@ -0,0 +1,10 @@
namespace Ryujinx.Graphics.Gpu.Memory
{
public enum ResourceName
{
Buffer,
Texture,
TexturePool,
SamplerPool
}
}

View File

@ -4,12 +4,13 @@ namespace Ryujinx.Graphics.Gpu.State
{
struct BlendState
{
public Bool SeparateAlpha;
public Boolean32 SeparateAlpha;
public BlendOp ColorOp;
public BlendFactor ColorSrcFactor;
public BlendFactor ColorDstFactor;
public BlendOp AlphaOp;
public BlendFactor AlphaSrcFactor;
public BlendFactor AlphaDstFactor;
public uint Padding;
}
}

View File

@ -1,17 +0,0 @@
namespace Ryujinx.Graphics.Gpu.State
{
struct Bool
{
private uint _value;
public bool IsTrue()
{
return (_value & 1) != 0;
}
public bool IsFalse()
{
return (_value & 1) == 0;
}
}
}

View File

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.Gpu.State
{
struct Boolean32
{
private uint _value;
public static implicit operator bool(Boolean32 value)
{
return (value._value & 1) != 0;
}
}
}

View File

@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.State
struct CopyTexture
{
public RtFormat Format;
public bool LinearLayout;
public Boolean32 LinearLayout;
public MemoryLayout MemoryLayout;
public int Depth;
public int Layer;

View File

@ -2,8 +2,8 @@ namespace Ryujinx.Graphics.Gpu.State
{
struct DepthBiasState
{
public Bool PointEnable;
public Bool LineEnable;
public Bool FillEnable;
public Boolean32 PointEnable;
public Boolean32 LineEnable;
public Boolean32 FillEnable;
}
}

View File

@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gpu.State
{
struct FaceState
{
public Bool CullEnable;
public Boolean32 CullEnable;
public FrontFace FrontFace;
public Face CullFace;
}

View File

@ -1,6 +1,4 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using System;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.State
@ -17,39 +15,54 @@ namespace Ryujinx.Graphics.Gpu.State
{
public MethodCallback Callback;
public StateWriteFlags WriteFlag;
public MethodOffset BaseOffset;
public int Stride;
public int Count;
public bool Modified;
}
private Register[] _registers;
public StateWriteFlags StateWriteFlags { get; set; }
public GpuState()
{
_backingMemory = new int[RegistersCount];
_registers = new Register[RegistersCount];
StateWriteFlags = StateWriteFlags.Any;
for (int index = 0; index < _registers.Length; index++)
{
_registers[index].BaseOffset = (MethodOffset)index;
_registers[index].Stride = 1;
_registers[index].Count = 1;
_registers[index].Modified = true;
}
foreach (var item in GpuStateTable.Table)
{
int totalRegs = item.Size * item.Count;
for (int regOffset = 0; regOffset < totalRegs; regOffset++)
{
int index = (int)item.Offset + regOffset;
_registers[index].BaseOffset = item.Offset;
_registers[index].Stride = item.Size;
_registers[index].Count = item.Count;
}
}
InitializeDefaultState();
InitializeStateWatchers();
}
public bool ExitEarly;
public void CallMethod(MethodParams meth)
{
if (ExitEarly)
{
return;
}
Register register = _registers[meth.Method];
if (_backingMemory[meth.Method] != meth.Argument)
{
StateWriteFlags |= register.WriteFlag;
_registers[(int)register.BaseOffset].Modified = true;
}
_backingMemory[meth.Method] = meth.Argument;
@ -67,264 +80,11 @@ namespace Ryujinx.Graphics.Gpu.State
return _backingMemory[offset];
}
public void RegisterCopyBufferCallback(MethodCallback callback)
{
RegisterCallback(0xc0, callback);
}
public void RegisterCopyTextureCallback(MethodCallback callback)
{
RegisterCallback(0x237, callback);
}
public void RegisterDrawEndCallback(MethodCallback callback)
{
RegisterCallback(0x585, callback);
}
public void RegisterDrawBeginCallback(MethodCallback callback)
{
RegisterCallback(0x586, callback);
}
public void RegisterSetIndexCountCallback(MethodCallback callback)
{
RegisterCallback(0x5f8, callback);
}
public void RegisterClearCallback(MethodCallback callback)
{
RegisterCallback(0x674, callback);
}
public void RegisterReportCallback(MethodCallback callback)
{
RegisterCallback(0x6c3, callback);
}
public void RegisterUniformBufferUpdateCallback(MethodCallback callback)
{
for (int index = 0; index < 16; index++)
{
RegisterCallback(0x8e4 + index, callback);
}
}
public void RegisterUniformBufferBind0Callback(MethodCallback callback)
{
RegisterCallback(0x904, callback);
}
public void RegisterUniformBufferBind1Callback(MethodCallback callback)
{
RegisterCallback(0x90c, callback);
}
public void RegisterUniformBufferBind2Callback(MethodCallback callback)
{
RegisterCallback(0x914, callback);
}
public void RegisterUniformBufferBind3Callback(MethodCallback callback)
{
RegisterCallback(0x91c, callback);
}
public void RegisterUniformBufferBind4Callback(MethodCallback callback)
{
RegisterCallback(0x924, callback);
}
public CopyTexture GetCopyDstTexture()
{
return Get<CopyTexture>(MethodOffset.CopyDstTexture);
}
public CopyTexture GetCopySrcTexture()
{
return Get<CopyTexture>(MethodOffset.CopySrcTexture);
}
public RtColorState GetRtColorState(int index)
{
return Get<RtColorState>(MethodOffset.RtColorState + 16 * index);
}
public CopyTextureControl GetCopyTextureControl()
{
return Get<CopyTextureControl>(MethodOffset.CopyTextureControl);
}
public CopyRegion GetCopyRegion()
{
return Get<CopyRegion>(MethodOffset.CopyRegion);
}
public ViewportTransform GetViewportTransform(int index)
{
return Get<ViewportTransform>(MethodOffset.ViewportTransform + 8 * index);
}
public ViewportExtents GetViewportExtents(int index)
{
return Get<ViewportExtents>(MethodOffset.ViewportExtents + 4 * index);
}
public VertexBufferDrawState GetVertexBufferDrawState()
{
return Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
}
public ClearColors GetClearColors()
{
return Get<ClearColors>(MethodOffset.ClearColors);
}
public float GetClearDepthValue()
{
return Get<float>(MethodOffset.ClearDepthValue);
}
public int GetClearStencilValue()
{
return _backingMemory[(int)MethodOffset.ClearStencilValue];
}
public StencilBackMasks GetStencilBackMasks()
{
return Get<StencilBackMasks>(MethodOffset.StencilBackMasks);
}
public RtDepthStencilState GetRtDepthStencilState()
{
return Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
}
public VertexAttribState GetVertexAttribState(int index)
{
return Get<VertexAttribState>(MethodOffset.VertexAttribState + index);
}
public Size3D GetRtDepthStencilSize()
{
return Get<Size3D>(MethodOffset.RtDepthStencilSize);
}
public Bool GetDepthTestEnable()
{
return Get<Bool>(MethodOffset.DepthTestEnable);
}
public CompareOp GetDepthTestFunc()
{
return Get<CompareOp>(MethodOffset.DepthTestFunc);
}
public Bool GetDepthWriteEnable()
{
return Get<Bool>(MethodOffset.DepthWriteEnable);
}
public Bool GetBlendEnable(int index)
{
return Get<Bool>(MethodOffset.BlendEnable + index);
}
public StencilTestState GetStencilTestState()
{
return Get<StencilTestState>(MethodOffset.StencilTestState);
}
public int GetBaseVertex()
{
return _backingMemory[(int)MethodOffset.FirstVertex];
}
public int GetBaseInstance()
{
return _backingMemory[(int)MethodOffset.FirstInstance];
}
public PoolState GetSamplerPoolState()
{
return Get<PoolState>(MethodOffset.SamplerPoolState);
}
public PoolState GetTexturePoolState()
{
return Get<PoolState>(MethodOffset.TexturePoolState);
}
public StencilBackTestState GetStencilBackTestState()
{
return Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
}
public TextureMsaaMode GetRtMsaaMode()
{
return Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
}
public GpuVa GetShaderBaseAddress()
{
return Get<GpuVa>(MethodOffset.ShaderBaseAddress);
}
public PrimitiveRestartState GetPrimitiveRestartState()
{
return Get<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState);
}
public IndexBufferState GetIndexBufferState()
{
return Get<IndexBufferState>(MethodOffset.IndexBufferState);
}
public FaceState GetFaceState()
{
return Get<FaceState>(MethodOffset.FaceState);
}
public ReportState GetReportState()
{
return Get<ReportState>(MethodOffset.ReportState);
}
public VertexBufferState GetVertexBufferState(int index)
{
return Get<VertexBufferState>(MethodOffset.VertexBufferState + 4 * index);
}
public BlendState GetBlendState(int index)
{
return Get<BlendState>(MethodOffset.BlendState + 8 * index);
}
public GpuVa GetVertexBufferEndAddress(int index)
{
return Get<GpuVa>(MethodOffset.VertexBufferEndAddress + 2 * index);
}
public ShaderState GetShaderState(int index)
{
return Get<ShaderState>(MethodOffset.ShaderState + 16 * index);
}
public UniformBufferState GetUniformBufferState()
{
return Get<UniformBufferState>(MethodOffset.UniformBufferState);
}
public void SetUniformBufferOffset(int offset)
{
_backingMemory[(int)MethodOffset.UniformBufferState + 3] = offset;
}
public int GetTextureBufferIndex()
{
return _backingMemory[(int)MethodOffset.TextureBufferIndex];
}
private void InitializeDefaultState()
{
// Depth ranges.
@ -341,69 +101,11 @@ namespace Ryujinx.Graphics.Gpu.State
_backingMemory[(int)MethodOffset.RtColorMask] = 0x1111;
}
private void InitializeStateWatchers()
public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback)
{
SetWriteStateFlag(MethodOffset.RtColorState, StateWriteFlags.RtColorState, 16 * 8);
SetWriteStateFlag(MethodOffset.ViewportTransform, StateWriteFlags.ViewportTransform, 8 * 8);
SetWriteStateFlag(MethodOffset.ViewportExtents, StateWriteFlags.ViewportTransform, 4 * 8);
SetWriteStateFlag<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState, StateWriteFlags.VertexBufferState);
SetWriteStateFlag<DepthBiasState>(MethodOffset.DepthBiasState, StateWriteFlags.DepthBiasState);
SetWriteStateFlag(MethodOffset.DepthBiasFactor, StateWriteFlags.DepthBiasState, 1);
SetWriteStateFlag(MethodOffset.DepthBiasUnits, StateWriteFlags.DepthBiasState, 1);
SetWriteStateFlag(MethodOffset.DepthBiasClamp, StateWriteFlags.DepthBiasState, 1);
SetWriteStateFlag<RtDepthStencilState>(MethodOffset.RtDepthStencilState, StateWriteFlags.RtDepthStencilState);
SetWriteStateFlag<Size3D> (MethodOffset.RtDepthStencilSize, StateWriteFlags.RtDepthStencilState);
SetWriteStateFlag(MethodOffset.DepthTestEnable, StateWriteFlags.DepthTestState, 1);
SetWriteStateFlag(MethodOffset.DepthWriteEnable, StateWriteFlags.DepthTestState, 1);
SetWriteStateFlag(MethodOffset.DepthTestFunc, StateWriteFlags.DepthTestState, 1);
SetWriteStateFlag(MethodOffset.VertexAttribState, StateWriteFlags.VertexAttribState, 16);
SetWriteStateFlag<StencilBackMasks> (MethodOffset.StencilBackMasks, StateWriteFlags.StencilTestState);
SetWriteStateFlag<StencilTestState> (MethodOffset.StencilTestState, StateWriteFlags.StencilTestState);
SetWriteStateFlag<StencilBackTestState>(MethodOffset.StencilBackTestState, StateWriteFlags.StencilTestState);
SetWriteStateFlag<PoolState>(MethodOffset.SamplerPoolState, StateWriteFlags.SamplerPoolState);
SetWriteStateFlag<PoolState>(MethodOffset.TexturePoolState, StateWriteFlags.TexturePoolState);
SetWriteStateFlag<ShaderState>(MethodOffset.ShaderBaseAddress, StateWriteFlags.ShaderState);
SetWriteStateFlag<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState, StateWriteFlags.PrimitiveRestartState);
SetWriteStateFlag<IndexBufferState>(MethodOffset.IndexBufferState, StateWriteFlags.IndexBufferState);
SetWriteStateFlag<FaceState>(MethodOffset.FaceState, StateWriteFlags.FaceState);
SetWriteStateFlag<RtColorMask>(MethodOffset.RtColorMask, StateWriteFlags.RtColorMask);
SetWriteStateFlag(MethodOffset.VertexBufferInstanced, StateWriteFlags.VertexBufferState, 16);
SetWriteStateFlag(MethodOffset.VertexBufferState, StateWriteFlags.VertexBufferState, 4 * 16);
SetWriteStateFlag(MethodOffset.VertexBufferEndAddress, StateWriteFlags.VertexBufferState, 2 * 16);
SetWriteStateFlag(MethodOffset.BlendEnable, StateWriteFlags.BlendState, 8);
SetWriteStateFlag(MethodOffset.BlendState, StateWriteFlags.BlendState, 8 * 8);
SetWriteStateFlag(MethodOffset.ShaderState, StateWriteFlags.ShaderState, 16 * 6);
SetWriteStateFlag(MethodOffset.TextureBufferIndex, StateWriteFlags.TexturePoolState, 1);
}
private void SetWriteStateFlag<T>(MethodOffset offset, StateWriteFlags flag)
{
SetWriteStateFlag(offset, flag, Marshal.SizeOf<T>());
}
private void SetWriteStateFlag(MethodOffset offset, StateWriteFlags flag, int size)
{
for (int index = 0; index < size; index++)
for (int index = 0; index < count; index++)
{
_registers[(int)offset + index].WriteFlag = flag;
_registers[(int)offset + index].Callback = callback;
}
}
@ -412,9 +114,37 @@ namespace Ryujinx.Graphics.Gpu.State
_registers[(int)offset].Callback = callback;
}
private void RegisterCallback(int offset, MethodCallback callback)
public bool QueryModified(params MethodOffset[] offsets)
{
_registers[offset].Callback = callback;
bool modified = false;
for (int index = 0; index < offsets.Length; index++)
{
modified |= QueryModified(offsets[index]);
}
return modified;
}
public bool QueryModified(MethodOffset offset)
{
bool modified = _registers[(int)offset].Modified;
_registers[(int)offset].Modified = false;
return modified;
}
public T Get<T>(MethodOffset offset, int index) where T : struct
{
Register register = _registers[(int)offset];
if ((uint)index >= register.Count)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
return Get<T>(offset + index * register.Stride);
}
public T Get<T>(MethodOffset offset) where T : struct

View File

@ -0,0 +1,56 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.State
{
static class GpuStateTable
{
public struct TableItem
{
public MethodOffset Offset { get; }
public int Size { get; }
public int Count { get; }
public TableItem(MethodOffset offset, Type type, int count)
{
int sizeInBytes = Marshal.SizeOf(type);
Debug.Assert((sizeInBytes & 3) == 0);
Offset = offset;
Size = sizeInBytes / 4;
Count = count;
}
}
public static TableItem[] Table = new TableItem[]
{
new TableItem(MethodOffset.RtColorState, typeof(RtColorState), 8),
new TableItem(MethodOffset.ViewportTransform, typeof(ViewportTransform), 8),
new TableItem(MethodOffset.ViewportExtents, typeof(ViewportExtents), 8),
new TableItem(MethodOffset.VertexBufferDrawState, typeof(VertexBufferDrawState), 1),
new TableItem(MethodOffset.DepthBiasState, typeof(DepthBiasState), 1),
new TableItem(MethodOffset.StencilBackMasks, typeof(StencilBackMasks), 1),
new TableItem(MethodOffset.RtDepthStencilState, typeof(RtDepthStencilState), 1),
new TableItem(MethodOffset.VertexAttribState, typeof(VertexAttribState), 16),
new TableItem(MethodOffset.RtDepthStencilSize, typeof(Size3D), 1),
new TableItem(MethodOffset.BlendEnable, typeof(Boolean32), 8),
new TableItem(MethodOffset.StencilTestState, typeof(StencilTestState), 1),
new TableItem(MethodOffset.SamplerPoolState, typeof(PoolState), 1),
new TableItem(MethodOffset.TexturePoolState, typeof(PoolState), 1),
new TableItem(MethodOffset.StencilBackTestState, typeof(StencilBackTestState), 1),
new TableItem(MethodOffset.ShaderBaseAddress, typeof(GpuVa), 1),
new TableItem(MethodOffset.PrimitiveRestartState, typeof(PrimitiveRestartState), 1),
new TableItem(MethodOffset.IndexBufferState, typeof(IndexBufferState), 1),
new TableItem(MethodOffset.VertexBufferInstanced, typeof(Boolean32), 16),
new TableItem(MethodOffset.FaceState, typeof(FaceState), 1),
new TableItem(MethodOffset.RtColorMask, typeof(RtColorMask), 8),
new TableItem(MethodOffset.VertexBufferState, typeof(VertexBufferState), 16),
new TableItem(MethodOffset.BlendState, typeof(BlendState), 8),
new TableItem(MethodOffset.VertexBufferEndAddress, typeof(GpuVa), 16),
new TableItem(MethodOffset.ShaderState, typeof(ShaderState), 6),
};
}
}

View File

@ -9,10 +9,5 @@ namespace Ryujinx.Graphics.Gpu.State
{
return Low | ((ulong)High << 32);
}
public bool IsNullPtr()
{
return (Low | High) == 0;
}
}
}

View File

@ -2,63 +2,76 @@ namespace Ryujinx.Graphics.Gpu.State
{
enum MethodOffset
{
Inline2MemoryParams = 0x60,
Inline2MemoryExecute = 0x6c,
Inline2MemoryPushData = 0x6d,
CopyDstTexture = 0x80,
CopySrcTexture = 0x8c,
DispatchParamsAddress = 0xad,
Dispatch = 0xaf,
CopyBufferParams = 0x100,
CopyBufferSwizzle = 0x1c2,
CopyBufferDstTexture = 0x1c3,
CopyBufferSrcTexture = 0x1ca,
RtColorState = 0x200,
CopyTextureControl = 0x223,
CopyRegion = 0x22c,
ViewportTransform = 0x280,
ViewportExtents = 0x300,
VertexBufferDrawState = 0x35d,
ClearColors = 0x360,
ClearDepthValue = 0x364,
ClearStencilValue = 0x368,
DepthBiasState = 0x370,
TextureBarrier = 0x378,
StencilBackMasks = 0x3d5,
InvalidateTextures = 0x3dd,
TextureBarrierTiled = 0x3df,
RtDepthStencilState = 0x3f8,
VertexAttribState = 0x458,
RtDepthStencilSize = 0x48a,
DepthTestEnable = 0x4b3,
DepthWriteEnable = 0x4ba,
DepthTestFunc = 0x4c3,
BlendEnable = 0x4d8,
StencilTestState = 0x4e0,
FirstVertex = 0x50d,
FirstInstance = 0x50e,
ResetCounter = 0x54c,
RtDepthStencilEnable = 0x54e,
ConditionState = 0x554,
SamplerPoolState = 0x557,
DepthBiasFactor = 0x55b,
TexturePoolState = 0x55d,
StencilBackTestState = 0x565,
DepthBiasUnits = 0x56f,
RtMsaaMode = 0x574,
ShaderBaseAddress = 0x582,
PrimitiveRestartState = 0x591,
IndexBufferState = 0x5f2,
DepthBiasClamp = 0x61f,
VertexBufferInstanced = 0x620,
FaceState = 0x646,
RtColorMask = 0x680,
ReportState = 0x6c0,
VertexBufferState = 0x700,
BlendState = 0x780,
VertexBufferEndAddress = 0x7c0,
ShaderState = 0x800,
UniformBufferState = 0x8e0,
TextureBufferIndex = 0x982
I2mParams = 0x60,
LaunchDma = 0x6c,
LoadInlineData = 0x6d,
CopyDstTexture = 0x80,
CopySrcTexture = 0x8c,
DispatchParamsAddress = 0xad,
Dispatch = 0xaf,
CopyBuffer = 0xc0,
CopyBufferParams = 0x100,
CopyBufferSwizzle = 0x1c2,
CopyBufferDstTexture = 0x1c3,
CopyBufferSrcTexture = 0x1ca,
RtColorState = 0x200,
CopyTextureControl = 0x223,
CopyRegion = 0x22c,
CopyTexture = 0x237,
ViewportTransform = 0x280,
ViewportExtents = 0x300,
VertexBufferDrawState = 0x35d,
ClearColors = 0x360,
ClearDepthValue = 0x364,
ClearStencilValue = 0x368,
DepthBiasState = 0x370,
TextureBarrier = 0x378,
StencilBackMasks = 0x3d5,
InvalidateTextures = 0x3dd,
TextureBarrierTiled = 0x3df,
RtDepthStencilState = 0x3f8,
VertexAttribState = 0x458,
RtDepthStencilSize = 0x48a,
DepthTestEnable = 0x4b3,
DepthWriteEnable = 0x4ba,
DepthTestFunc = 0x4c3,
BlendEnable = 0x4d8,
StencilTestState = 0x4e0,
FirstVertex = 0x50d,
FirstInstance = 0x50e,
ResetCounter = 0x54c,
RtDepthStencilEnable = 0x54e,
ConditionState = 0x554,
SamplerPoolState = 0x557,
DepthBiasFactor = 0x55b,
TexturePoolState = 0x55d,
StencilBackTestState = 0x565,
DepthBiasUnits = 0x56f,
RtMsaaMode = 0x574,
ShaderBaseAddress = 0x582,
DrawEnd = 0x585,
DrawBegin = 0x586,
PrimitiveRestartState = 0x591,
IndexBufferState = 0x5f2,
IndexBufferCount = 0x5f8,
DepthBiasClamp = 0x61f,
VertexBufferInstanced = 0x620,
FaceState = 0x646,
Clear = 0x674,
RtColorMask = 0x680,
ReportState = 0x6c0,
Report = 0x6c3,
VertexBufferState = 0x700,
BlendState = 0x780,
VertexBufferEndAddress = 0x7c0,
ShaderState = 0x800,
UniformBufferState = 0x8e0,
UniformBufferUpdateData = 0x8e4,
UniformBufferBindVertex = 0x904,
UniformBufferBindTessControl = 0x90c,
UniformBufferBindTessEvaluation = 0x914,
UniformBufferBindGeometry = 0x91c,
UniformBufferBindFragment = 0x924,
TextureBufferIndex = 0x982
}
}

View File

@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Gpu.State
{
struct PrimitiveRestartState
{
public bool Enable;
public int Index;
public Boolean32 Enable;
public int Index;
}
}

View File

@ -9,5 +9,13 @@ namespace Ryujinx.Graphics.Gpu.State
public MemoryLayout MemoryLayout;
public int Depth;
public int LayerSize;
public int BaseLayer;
public int Unknown0x24;
public int Padding0;
public int Padding1;
public int Padding2;
public int Padding3;
public int Padding4;
public int Padding5;
}
}

View File

@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gpu.State
D32Float = 0xa,
D16Unorm = 0x13,
D24UnormS8Uint = 0x14,
D24Unorm = 0x15,
S8UintD24Unorm = 0x16,
S8Uint = 0x17,
D32FloatS8Uint = 0x19,
R32G32B32A32Float = 0xc0,
@ -74,6 +76,8 @@ namespace Ryujinx.Graphics.Gpu.State
case RtFormat.D32Float: return new FormatInfo(Format.D32Float, 1, 1, 4);
case RtFormat.D16Unorm: return new FormatInfo(Format.D16Unorm, 1, 1, 2);
case RtFormat.D24UnormS8Uint: return new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4);
case RtFormat.D24Unorm: return new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4);
case RtFormat.S8UintD24Unorm: return new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4);
case RtFormat.S8Uint: return new FormatInfo(Format.S8Uint, 1, 1, 1);
case RtFormat.D32FloatS8Uint: return new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8);
case RtFormat.R32G32B32A32Float: return new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16);

View File

@ -10,6 +10,14 @@ namespace Ryujinx.Graphics.Gpu.State
public uint Unknown0x14;
public uint Unknown0x18;
public uint Unknown0x1c;
public uint Unknown0x20;
public uint Unknown0x24;
public uint Unknown0x28;
public uint Unknown0x2c;
public uint Unknown0x30;
public uint Unknown0x34;
public uint Unknown0x38;
public uint Unknown0x3c;
public bool UnpackEnable()
{

View File

@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.State
{
struct StencilBackTestState
{
public Bool TwoSided;
public Boolean32 TwoSided;
public StencilOp BackSFail;
public StencilOp BackDpFail;
public StencilOp BackDpPass;

View File

@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.State
{
struct StencilTestState
{
public Bool Enable;
public Boolean32 Enable;
public StencilOp FrontSFail;
public StencilOp FrontDpFail;
public StencilOp FrontDpPass;

View File

@ -906,12 +906,15 @@ namespace Ryujinx.Graphics.OpenGL
private void RestoreComponentMask(int index)
{
GL.ColorMask(
index,
(_componentMasks[index] & 1u) != 0,
(_componentMasks[index] & 2u) != 0,
(_componentMasks[index] & 4u) != 0,
(_componentMasks[index] & 8u) != 0);
if (_componentMasks != null)
{
GL.ColorMask(
index,
(_componentMasks[index] & 1u) != 0,
(_componentMasks[index] & 2u) != 0,
(_componentMasks[index] & 4u) != 0,
(_componentMasks[index] & 8u) != 0);
}
}
public void RebindProgram()

View File

@ -6,6 +6,5 @@ namespace Ryujinx.Graphics.Shader.Decoders
Green = 1 << 1,
Blue = 1 << 2,
Alpha = 1 << 3
}
}

View File

@ -2,6 +2,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
{
enum SystemRegister
{
ThreadId = 0x20,
ThreadIdX = 0x21,
ThreadIdY = 0x22,
ThreadIdZ = 0x23,

View File

@ -27,6 +27,20 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (sysReg)
{
case SystemRegister.ThreadId:
{
Operand tidX = Attribute(AttributeConsts.ThreadIdX);
Operand tidY = Attribute(AttributeConsts.ThreadIdY);
Operand tidZ = Attribute(AttributeConsts.ThreadIdZ);
tidY = context.ShiftLeft(tidY, Const(16));
tidZ = context.ShiftLeft(tidZ, Const(26));
src = context.BitwiseOr(tidX, context.BitwiseOr(tidY, tidZ));
break;
}
case SystemRegister.ThreadIdX: src = Attribute(AttributeConsts.ThreadIdX); break;
case SystemRegister.ThreadIdY: src = Attribute(AttributeConsts.ThreadIdY); break;
case SystemRegister.ThreadIdZ: src = Attribute(AttributeConsts.ThreadIdZ); break;

View File

@ -59,6 +59,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.ExponentB2, VariableType.Scalar, VariableType.Scalar);
Add(Instruction.Floor, VariableType.F32, VariableType.F32);
Add(Instruction.FusedMultiplyAdd, VariableType.F32, VariableType.F32, VariableType.F32, VariableType.F32);
Add(Instruction.ImageLoad, VariableType.F32);
Add(Instruction.ImageStore, VariableType.None);
Add(Instruction.IsNan, VariableType.Bool, VariableType.F32);
Add(Instruction.LoadAttribute, VariableType.F32, VariableType.S32, VariableType.S32);
Add(Instruction.LoadConstant, VariableType.F32, VariableType.S32, VariableType.S32);
@ -105,7 +107,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public static VariableType GetSrcVarType(Instruction inst, int index)
{
if (inst == Instruction.TextureSample)
// TODO: Return correct type depending on source index,
// that can improve the decompiler output.
if (inst == Instruction.TextureSample ||
inst == Instruction.ImageLoad ||
inst == Instruction.ImageStore)
{
return VariableType.F32;
}

View File

@ -59,9 +59,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
_cpuMemory.WriteBytes((long)address, data.ToArray());
}
public (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size)
public (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, ResourceName name)
{
return _cpuMemory.GetModifiedRanges(address, size);
return _cpuMemory.GetModifiedRanges(address, size, (int)name);
}
public int GetPageSize()