Implement vertex instancing (#381)

This commit is contained in:
ReinUsesLisp 2018-08-25 01:16:58 -03:00 committed by gdkchan
parent da7e702751
commit a42ab2e40c
7 changed files with 82 additions and 20 deletions

View file

@ -27,6 +27,8 @@ namespace Ryujinx.HLE.Gpu.Engines
private List<long>[] UploadedKeys;
private int CurrentInstance = 0;
public NvGpuEngine3d(NvGpu Gpu)
{
this.Gpu = Gpu;
@ -654,10 +656,25 @@ namespace Ryujinx.HLE.Gpu.Engines
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2);
long VboKey = Vmm.GetPhysicalAddress(VertexPosition);
int VertexDivisor = ReadRegister(NvGpuEngine3dReg.VertexArrayNDivisor + Index * 4);
bool Instanced = (ReadRegister(NvGpuEngine3dReg.VertexArrayNInstance + Index) & 1) != 0;
int Stride = Control & 0xfff;
if (Instanced && VertexDivisor != 0)
{
VertexPosition += Stride * (CurrentInstance / VertexDivisor);
}
if (VertexPosition > VertexEndPos)
{
//Instance is invalid, ignore the draw call
continue;
}
long VboKey = Vmm.GetPhysicalAddress(VertexPosition);
long VbSize = (VertexEndPos - VertexPosition) + 1;
bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, VbSize);
@ -669,10 +686,12 @@ namespace Ryujinx.HLE.Gpu.Engines
Gpu.Renderer.Rasterizer.CreateVbo(VboKey, (int)VbSize, DataAddress);
}
State.VertexBindings[Index].Enabled = true;
State.VertexBindings[Index].Stride = Stride;
State.VertexBindings[Index].VboKey = VboKey;
State.VertexBindings[Index].Attribs = Attribs[Index].ToArray();
State.VertexBindings[Index].Enabled = true;
State.VertexBindings[Index].Stride = Stride;
State.VertexBindings[Index].VboKey = VboKey;
State.VertexBindings[Index].Instanced = Instanced;
State.VertexBindings[Index].Divisor = VertexDivisor;
State.VertexBindings[Index].Attribs = Attribs[Index].ToArray();
}
}
@ -683,6 +702,25 @@ namespace Ryujinx.HLE.Gpu.Engines
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
bool InstanceNext = ((PrimCtrl >> 26) & 1) != 0;
bool InstanceCont = ((PrimCtrl >> 27) & 1) != 0;
if (InstanceNext && InstanceCont)
{
throw new InvalidOperationException("GPU tried to increase and reset instance count at the same time");
}
if (InstanceNext)
{
CurrentInstance++;
}
else if (!InstanceCont)
{
CurrentInstance = 0;
}
State.Instance = CurrentInstance;
Gpu.Renderer.Pipeline.Bind(State);
if (IndexCount != 0)