Texture/Vertex/Index data cache (#132)

* Initial implementation of the texture cache

* Cache vertex and index data aswell, some cleanup

* Improve handling of the cache by storing cached ranges on a list for each page

* Delete old data from the caches automatically, ensure that the cache is cleaned when the mapping/size changes, and some general cleanup
This commit is contained in:
gdkchan 2018-06-08 21:15:56 -03:00 committed by GitHub
parent 6fe51f9705
commit 231fae1a4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 837 additions and 819 deletions

View file

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace Ryujinx.Core.Gpu
{
public class NvGpuEngine3d : INvGpuEngine
class NvGpuEngine3d : INvGpuEngine
{
public int[] Registers { get; private set; }
@ -261,6 +261,8 @@ namespace Ryujinx.Core.Gpu
long TextureAddress = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff;
long Tag = TextureAddress;
TextureAddress = Vmm.GetPhysicalAddress(TextureAddress);
if (IsFrameBufferPosition(TextureAddress))
@ -273,10 +275,25 @@ namespace Ryujinx.Core.Gpu
}
else
{
GalTexture Texture = TextureFactory.MakeTexture(Gpu, Vmm, TicPosition);
GalTexture NewTexture = TextureFactory.MakeTexture(Vmm, TicPosition);
Gpu.Renderer.SetTextureAndSampler(TexIndex, Texture, Sampler);
Gpu.Renderer.BindTexture(TexIndex);
long Size = (uint)TextureHelper.GetTextureSize(NewTexture);
if (Gpu.Renderer.TryGetCachedTexture(Tag, Size, out GalTexture Texture))
{
if (NewTexture.Equals(Texture) && !Vmm.IsRegionModified(Tag, Size, NvGpuBufferType.Texture))
{
Gpu.Renderer.BindTexture(Tag, TexIndex);
return;
}
}
byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition);
Gpu.Renderer.SetTextureAndSampler(Tag, Data, NewTexture, Sampler);
Gpu.Renderer.BindTexture(Tag, TexIndex);
}
}
@ -330,11 +347,18 @@ namespace Ryujinx.Core.Gpu
if (IndexSize != 0)
{
int BufferSize = IndexCount * IndexSize;
int IbSize = IndexCount * IndexSize;
byte[] Data = Vmm.ReadBytes(IndexPosition, BufferSize);
bool IboCached = Gpu.Renderer.IsIboCached(IndexPosition, (uint)IbSize);
Gpu.Renderer.SetIndexArray(Data, IndexFormat);
if (!IboCached || Vmm.IsRegionModified(IndexPosition, (uint)IbSize, NvGpuBufferType.Index))
{
byte[] Data = Vmm.ReadBytes(IndexPosition, (uint)IbSize);
Gpu.Renderer.CreateIbo(IndexPosition, Data);
}
Gpu.Renderer.SetIndexArray(IndexPosition, IbSize, IndexFormat);
}
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
@ -359,10 +383,17 @@ namespace Ryujinx.Core.Gpu
((Packed >> 31) & 0x1) != 0));
}
int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst);
int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount);
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
for (int Index = 0; Index < 32; Index++)
{
int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst);
int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount);
if (Attribs[Index] == null)
{
continue;
}
int Control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + Index * 4);
@ -378,39 +409,38 @@ namespace Ryujinx.Core.Gpu
int Stride = Control & 0xfff;
long Size = 0;
long VbSize = 0;
if (IndexCount != 0)
{
Size = (VertexEndPos - VertexPosition) + 1;
VbSize = (VertexEndPos - VertexPosition) + 1;
}
else
{
Size = VertexCount;
VbSize = VertexCount * Stride;
}
//TODO: Support cases where the Stride is 0.
//In this case, we need to use the size of the attribute.
Size *= Stride;
bool VboCached = Gpu.Renderer.IsVboCached(VertexPosition, VbSize);
byte[] Data = Vmm.ReadBytes(VertexPosition, Size);
GalVertexAttrib[] AttribArray = Attribs[Index]?.ToArray() ?? new GalVertexAttrib[0];
Gpu.Renderer.SetVertexArray(Index, Stride, Data, AttribArray);
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
if (IndexCount != 0)
if (!VboCached || Vmm.IsRegionModified(VertexPosition, VbSize, NvGpuBufferType.Vertex))
{
Gpu.Renderer.DrawElements(Index, IndexFirst, PrimType);
}
else
{
Gpu.Renderer.DrawArrays(Index, VertexFirst, VertexCount, PrimType);
byte[] Data = Vmm.ReadBytes(VertexPosition, VbSize);
Gpu.Renderer.CreateVbo(VertexPosition, Data);
}
Gpu.Renderer.SetVertexArray(Index, Stride, VertexPosition, Attribs[Index].ToArray());
}
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
if (IndexCount != 0)
{
Gpu.Renderer.DrawElements(IndexPosition, IndexFirst, PrimType);
}
else
{
Gpu.Renderer.DrawArrays(VertexFirst, VertexCount, PrimType);
}
}