1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
using Ryujinx.Graphics.Memory;
using Ryujinx.Graphics.Texture;
using System.Collections.Generic;
namespace Ryujinx.Graphics
{
public class NvGpuEngineDma : INvGpuEngine
{
public int[] Registers { get; private set; }
private NvGpu Gpu;
private Dictionary<int, NvGpuMethod> Methods;
public NvGpuEngineDma(NvGpu Gpu)
{
this.Gpu = Gpu;
Registers = new int[0x1d6];
Methods = new Dictionary<int, NvGpuMethod>();
void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method)
{
while (Count-- > 0)
{
Methods.Add(Meth, Method);
Meth += Stride;
}
}
AddMethod(0xc0, 1, 1, Execute);
}
public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method))
{
Method(Vmm, PBEntry);
}
else
{
WriteRegister(PBEntry);
}
}
private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
{
int Control = PBEntry.Arguments[0];
bool SrcLinear = ((Control >> 7) & 1) != 0;
bool DstLinear = ((Control >> 8) & 1) != 0;
long SrcAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.SrcAddress);
long DstAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.DstAddress);
int SrcPitch = ReadRegister(NvGpuEngineDmaReg.SrcPitch);
int DstPitch = ReadRegister(NvGpuEngineDmaReg.DstPitch);
int DstBlkDim = ReadRegister(NvGpuEngineDmaReg.DstBlkDim);
int DstSizeX = ReadRegister(NvGpuEngineDmaReg.DstSizeX);
int DstSizeY = ReadRegister(NvGpuEngineDmaReg.DstSizeY);
int DstSizeZ = ReadRegister(NvGpuEngineDmaReg.DstSizeZ);
int DstPosXY = ReadRegister(NvGpuEngineDmaReg.DstPosXY);
int DstPosZ = ReadRegister(NvGpuEngineDmaReg.DstPosZ);
int SrcBlkDim = ReadRegister(NvGpuEngineDmaReg.SrcBlkDim);
int SrcSizeX = ReadRegister(NvGpuEngineDmaReg.SrcSizeX);
int SrcSizeY = ReadRegister(NvGpuEngineDmaReg.SrcSizeY);
int SrcSizeZ = ReadRegister(NvGpuEngineDmaReg.SrcSizeZ);
int SrcPosXY = ReadRegister(NvGpuEngineDmaReg.SrcPosXY);
int SrcPosZ = ReadRegister(NvGpuEngineDmaReg.SrcPosZ);
int DstPosX = (DstPosXY >> 0) & 0xffff;
int DstPosY = (DstPosXY >> 16) & 0xffff;
int SrcPosX = (SrcPosXY >> 0) & 0xffff;
int SrcPosY = (SrcPosXY >> 16) & 0xffff;
int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf);
int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf);
ISwizzle SrcSwizzle;
if (SrcLinear)
{
SrcSwizzle = new LinearSwizzle(SrcPitch, 1);
}
else
{
SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, 1, SrcBlockHeight);
}
ISwizzle DstSwizzle;
if (DstLinear)
{
DstSwizzle = new LinearSwizzle(DstPitch, 1);
}
else
{
DstSwizzle = new BlockLinearSwizzle(DstSizeX, 1, DstBlockHeight);
}
for (int Y = 0; Y < DstSizeY; Y++)
for (int X = 0; X < DstSizeX; X++)
{
long SrcOffset = SrcAddress + (uint)SrcSwizzle.GetSwizzleOffset(X, Y);
long DstOffset = DstAddress + (uint)DstSwizzle.GetSwizzleOffset(X, Y);
Vmm.WriteByte(DstOffset, Vmm.ReadByte(SrcOffset));
}
}
private long MakeInt64From2xInt32(NvGpuEngineDmaReg Reg)
{
return
(long)Registers[(int)Reg + 0] << 32 |
(uint)Registers[(int)Reg + 1];
}
private void WriteRegister(NvGpuPBEntry PBEntry)
{
int ArgsCount = PBEntry.Arguments.Count;
if (ArgsCount > 0)
{
Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1];
}
}
private int ReadRegister(NvGpuEngineDmaReg Reg)
{
return Registers[(int)Reg];
}
private void WriteRegister(NvGpuEngineDmaReg Reg, int Value)
{
Registers[(int)Reg] = Value;
}
}
}
|