mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-10-01 12:30:00 +02:00
fbb4019ed5
* Make GPU memory manager a member of GPU channel * Move physical memory instance to the memory manager, and the caches to the physical memory * PR feedback
134 lines
No EOL
4.2 KiB
C#
134 lines
No EOL
4.2 KiB
C#
using Ryujinx.Common;
|
|
using Ryujinx.Graphics.Gpu.State;
|
|
using Ryujinx.Graphics.Texture;
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Ryujinx.Graphics.Gpu.Engine
|
|
{
|
|
partial class Methods
|
|
{
|
|
private Inline2MemoryParams _params;
|
|
|
|
private bool _isLinear;
|
|
|
|
private int _offset;
|
|
private int _size;
|
|
|
|
private bool _finished;
|
|
|
|
private int[] _buffer;
|
|
|
|
/// <summary>
|
|
/// Launches Inline-to-Memory engine DMA copy.
|
|
/// </summary>
|
|
/// <param name="state">Current GPU state</param>
|
|
/// <param name="argument">Method call argument</param>
|
|
public void LaunchDma(GpuState state, int argument)
|
|
{
|
|
_params = state.Get<Inline2MemoryParams>(MethodOffset.I2mParams);
|
|
|
|
_isLinear = (argument & 1) != 0;
|
|
|
|
_offset = 0;
|
|
_size = _params.LineLengthIn * _params.LineCount;
|
|
|
|
int count = BitUtils.DivRoundUp(_size, 4);
|
|
|
|
if (_buffer == null || _buffer.Length < count)
|
|
{
|
|
_buffer = new int[count];
|
|
}
|
|
|
|
ulong dstBaseAddress = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
|
|
|
|
// Trigger read tracking, to flush any managed resources in the destination region.
|
|
state.Channel.MemoryManager.Physical.GetSpan(dstBaseAddress, _size, true);
|
|
|
|
_finished = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pushes a word of data to the Inline-to-Memory engine.
|
|
/// </summary>
|
|
/// <param name="state">Current GPU state</param>
|
|
/// <param name="argument">Method call argument</param>
|
|
public void LoadInlineData(GpuState state, int argument)
|
|
{
|
|
if (!_finished)
|
|
{
|
|
_buffer[_offset++] = argument;
|
|
|
|
if (_offset * 4 >= _size)
|
|
{
|
|
FinishTransfer(state);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs actual copy of the inline data after the transfer is finished.
|
|
/// </summary>
|
|
/// <param name="state">Current GPU state</param>
|
|
private void FinishTransfer(GpuState state)
|
|
{
|
|
Span<byte> data = MemoryMarshal.Cast<int, byte>(_buffer).Slice(0, _size);
|
|
|
|
if (_isLinear && _params.LineCount == 1)
|
|
{
|
|
ulong address = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
|
|
|
|
state.Channel.MemoryManager.Physical.Write(address, data);
|
|
}
|
|
else
|
|
{
|
|
var dstCalculator = new OffsetCalculator(
|
|
_params.DstWidth,
|
|
_params.DstHeight,
|
|
_params.DstStride,
|
|
_isLinear,
|
|
_params.DstMemoryLayout.UnpackGobBlocksInY(),
|
|
1);
|
|
|
|
int srcOffset = 0;
|
|
|
|
ulong dstBaseAddress = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
|
|
|
|
for (int y = _params.DstY; y < _params.DstY + _params.LineCount; y++)
|
|
{
|
|
int x1 = _params.DstX;
|
|
int x2 = _params.DstX + _params.LineLengthIn;
|
|
int x2Trunc = _params.DstX + BitUtils.AlignDown(_params.LineLengthIn, 16);
|
|
|
|
int x;
|
|
|
|
for (x = x1; x < x2Trunc; x += 16, srcOffset += 16)
|
|
{
|
|
int dstOffset = dstCalculator.GetOffset(x, y);
|
|
|
|
ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
|
|
|
|
Span<byte> pixel = data.Slice(srcOffset, 16);
|
|
|
|
state.Channel.MemoryManager.Physical.Write(dstAddress, pixel);
|
|
}
|
|
|
|
for (; x < x2; x++, srcOffset++)
|
|
{
|
|
int dstOffset = dstCalculator.GetOffset(x, y);
|
|
|
|
ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
|
|
|
|
Span<byte> pixel = data.Slice(srcOffset, 1);
|
|
|
|
state.Channel.MemoryManager.Physical.Write(dstAddress, pixel);
|
|
}
|
|
}
|
|
}
|
|
|
|
_finished = true;
|
|
|
|
_context.AdvanceSequence();
|
|
}
|
|
}
|
|
} |