Add ConstBuffer cache
This commit is contained in:
parent
ce96a45685
commit
bb4c39411a
9 changed files with 173 additions and 100 deletions
18
Ryujinx.Graphics/Gal/IGalConstBuffer.cs
Normal file
18
Ryujinx.Graphics/Gal/IGalConstBuffer.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal
|
||||||
|
{
|
||||||
|
public interface IGalConstBuffer
|
||||||
|
{
|
||||||
|
void LockCache();
|
||||||
|
void UnlockCache();
|
||||||
|
|
||||||
|
void Create(long Key, long Size);
|
||||||
|
|
||||||
|
bool IsCached(long Key, long Size);
|
||||||
|
|
||||||
|
void SetData(long Key, long Size, IntPtr HostAddress);
|
||||||
|
|
||||||
|
void Bind(GalShaderType ShaderType, int Index, long Key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
IGalBlend Blend { get; }
|
IGalBlend Blend { get; }
|
||||||
|
|
||||||
|
IGalConstBuffer Buffer { get; }
|
||||||
|
|
||||||
IGalFrameBuffer FrameBuffer { get; }
|
IGalFrameBuffer FrameBuffer { get; }
|
||||||
|
|
||||||
IGalRasterizer Rasterizer { get; }
|
IGalRasterizer Rasterizer { get; }
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gal
|
||||||
|
|
||||||
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
|
||||||
|
|
||||||
void SetConstBuffer(long Key, int Cbuf, int DataSize, IntPtr HostAddress);
|
void BindConstBuffers();
|
||||||
|
|
||||||
void EnsureTextureBinding(string UniformName, int Value);
|
void EnsureTextureBinding(string UniformName, int Value);
|
||||||
|
|
||||||
|
|
78
Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
Normal file
78
Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
{
|
||||||
|
class OGLConstBuffer : IGalConstBuffer
|
||||||
|
{
|
||||||
|
public const int ConstBuffersPerStage = 18;
|
||||||
|
|
||||||
|
private OGLCachedResource<OGLStreamBuffer> Cache;
|
||||||
|
|
||||||
|
private long[][] Keys;
|
||||||
|
|
||||||
|
public OGLConstBuffer()
|
||||||
|
{
|
||||||
|
Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer);
|
||||||
|
|
||||||
|
Keys = new long[5][];
|
||||||
|
|
||||||
|
for (int i = 0; i < Keys.Length; i++)
|
||||||
|
{
|
||||||
|
Keys[i] = new long[ConstBuffersPerStage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LockCache()
|
||||||
|
{
|
||||||
|
Cache.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnlockCache()
|
||||||
|
{
|
||||||
|
Cache.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Create(long Key, long Size)
|
||||||
|
{
|
||||||
|
OGLStreamBuffer Buffer = new OGLStreamBuffer(BufferTarget.UniformBuffer, Size);
|
||||||
|
|
||||||
|
Cache.AddOrUpdate(Key, Buffer, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCached(long Key, long Size)
|
||||||
|
{
|
||||||
|
return Cache.TryGetSize(Key, out long CachedSize) && CachedSize == Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetData(long Key, long Size, IntPtr HostAddress)
|
||||||
|
{
|
||||||
|
if (!Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer.SetData(Size, HostAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Bind(GalShaderType Stage, int Index, long Key)
|
||||||
|
{
|
||||||
|
Keys[(int)Stage][Index] = Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PipelineBind(GalShaderType Stage, int Index, int BindingIndex)
|
||||||
|
{
|
||||||
|
long Key = Keys[(int)Stage][Index];
|
||||||
|
|
||||||
|
if (Key != 0 && Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
|
||||||
|
{
|
||||||
|
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, BindingIndex, Buffer.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DeleteBuffer(OGLStreamBuffer Buffer)
|
||||||
|
{
|
||||||
|
Buffer.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public IGalBlend Blend { get; private set; }
|
public IGalBlend Blend { get; private set; }
|
||||||
|
|
||||||
|
public IGalConstBuffer Buffer { get; private set; }
|
||||||
|
|
||||||
public IGalFrameBuffer FrameBuffer { get; private set; }
|
public IGalFrameBuffer FrameBuffer { get; private set; }
|
||||||
|
|
||||||
public IGalRasterizer Rasterizer { get; private set; }
|
public IGalRasterizer Rasterizer { get; private set; }
|
||||||
|
@ -21,11 +23,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
Blend = new OGLBlend();
|
Blend = new OGLBlend();
|
||||||
|
|
||||||
|
Buffer = new OGLConstBuffer();
|
||||||
|
|
||||||
FrameBuffer = new OGLFrameBuffer();
|
FrameBuffer = new OGLFrameBuffer();
|
||||||
|
|
||||||
Rasterizer = new OGLRasterizer();
|
Rasterizer = new OGLRasterizer();
|
||||||
|
|
||||||
Shader = new OGLShader();
|
Shader = new OGLShader(Buffer as OGLConstBuffer);
|
||||||
|
|
||||||
Texture = new OGLTexture();
|
Texture = new OGLTexture();
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ using Buffer = System.Buffer;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public class OGLShader : IGalShader
|
class OGLShader : IGalShader
|
||||||
{
|
{
|
||||||
private class ShaderStage : IDisposable
|
private class ShaderStage : IDisposable
|
||||||
{
|
{
|
||||||
|
@ -71,8 +71,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
public ShaderStage Fragment;
|
public ShaderStage Fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int ConstBuffersPerStage = 18;
|
|
||||||
|
|
||||||
private ShaderProgram Current;
|
private ShaderProgram Current;
|
||||||
|
|
||||||
private ConcurrentDictionary<long, ShaderStage> Stages;
|
private ConcurrentDictionary<long, ShaderStage> Stages;
|
||||||
|
@ -81,20 +79,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
public int CurrentProgramHandle { get; private set; }
|
public int CurrentProgramHandle { get; private set; }
|
||||||
|
|
||||||
private OGLStreamBuffer[][] ConstBuffers;
|
private OGLConstBuffer Buffer;
|
||||||
|
|
||||||
public OGLShader()
|
public OGLShader(OGLConstBuffer Buffer)
|
||||||
{
|
{
|
||||||
|
this.Buffer = Buffer;
|
||||||
|
|
||||||
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
Stages = new ConcurrentDictionary<long, ShaderStage>();
|
||||||
|
|
||||||
Programs = new Dictionary<ShaderProgram, int>();
|
Programs = new Dictionary<ShaderProgram, int>();
|
||||||
|
|
||||||
ConstBuffers = new OGLStreamBuffer[5][];
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
ConstBuffers[i] = new OGLStreamBuffer[ConstBuffersPerStage];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
public void Create(IGalMemory Memory, long Key, GalShaderType Type)
|
||||||
|
@ -153,19 +146,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
return Enumerable.Empty<ShaderDeclInfo>();
|
return Enumerable.Empty<ShaderDeclInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetConstBuffer(long Key, int Cbuf, int DataSize, IntPtr HostAddress)
|
public void BindConstBuffers()
|
||||||
{
|
{
|
||||||
if (Stages.TryGetValue(Key, out ShaderStage Stage))
|
int FreeBinding = 0;
|
||||||
|
|
||||||
|
void BindIfNotNull(ShaderStage Stage)
|
||||||
{
|
{
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
|
if (Stage != null)
|
||||||
{
|
{
|
||||||
OGLStreamBuffer Buffer = GetConstBuffer(Stage.Type, Cbuf);
|
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
||||||
|
{
|
||||||
|
Buffer.PipelineBind(Stage.Type, DeclInfo.Cbuf, FreeBinding);
|
||||||
|
|
||||||
int Size = Math.Min(DataSize, Buffer.Size);
|
FreeBinding++;
|
||||||
|
}
|
||||||
Buffer.SetData(Size, HostAddress);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BindIfNotNull(Current.Vertex);
|
||||||
|
BindIfNotNull(Current.TessControl);
|
||||||
|
BindIfNotNull(Current.TessEvaluation);
|
||||||
|
BindIfNotNull(Current.Geometry);
|
||||||
|
BindIfNotNull(Current.Fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureTextureBinding(string UniformName, int Value)
|
public void EnsureTextureBinding(string UniformName, int Value)
|
||||||
|
@ -257,11 +259,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.UseProgram(Handle);
|
GL.UseProgram(Handle);
|
||||||
|
|
||||||
if (CurrentProgramHandle != Handle)
|
|
||||||
{
|
|
||||||
BindUniformBuffers(Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentProgramHandle = Handle;
|
CurrentProgramHandle = Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,51 +304,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
BindUniformBlocksIfNotNull(Current.Fragment);
|
BindUniformBlocksIfNotNull(Current.Fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindUniformBuffers(int ProgramHandle)
|
|
||||||
{
|
|
||||||
int FreeBinding = 0;
|
|
||||||
|
|
||||||
void BindUniformBuffersIfNotNull(ShaderStage Stage)
|
|
||||||
{
|
|
||||||
if (Stage != null)
|
|
||||||
{
|
|
||||||
foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
|
|
||||||
{
|
|
||||||
OGLStreamBuffer Buffer = GetConstBuffer(Stage.Type, DeclInfo.Cbuf);
|
|
||||||
|
|
||||||
GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, Buffer.Handle);
|
|
||||||
|
|
||||||
FreeBinding++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BindUniformBuffersIfNotNull(Current.Vertex);
|
|
||||||
BindUniformBuffersIfNotNull(Current.TessControl);
|
|
||||||
BindUniformBuffersIfNotNull(Current.TessEvaluation);
|
|
||||||
BindUniformBuffersIfNotNull(Current.Geometry);
|
|
||||||
BindUniformBuffersIfNotNull(Current.Fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OGLStreamBuffer GetConstBuffer(GalShaderType StageType, int Cbuf)
|
|
||||||
{
|
|
||||||
int StageIndex = (int)StageType;
|
|
||||||
|
|
||||||
OGLStreamBuffer Buffer = ConstBuffers[StageIndex][Cbuf];
|
|
||||||
|
|
||||||
if (Buffer == null)
|
|
||||||
{
|
|
||||||
//Allocate a maximum of 64 KiB
|
|
||||||
int Size = Math.Min(GL.GetInteger(GetPName.MaxUniformBlockSize), 64 * 1024);
|
|
||||||
|
|
||||||
Buffer = new OGLStreamBuffer(BufferTarget.UniformBuffer, Size);
|
|
||||||
|
|
||||||
ConstBuffers[StageIndex][Cbuf] = Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CompileAndCheck(int Handle, string Code)
|
public static void CompileAndCheck(int Handle, string Code)
|
||||||
{
|
{
|
||||||
GL.ShaderSource(Handle, Code);
|
GL.ShaderSource(Handle, Code);
|
||||||
|
|
|
@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
public int Handle { get; protected set; }
|
public int Handle { get; protected set; }
|
||||||
|
|
||||||
public int Size { get; protected set; }
|
public long Size { get; protected set; }
|
||||||
|
|
||||||
protected BufferTarget Target { get; private set; }
|
protected BufferTarget Target { get; private set; }
|
||||||
|
|
||||||
public OGLStreamBuffer(BufferTarget Target, int Size)
|
public OGLStreamBuffer(BufferTarget Target, long Size)
|
||||||
{
|
{
|
||||||
this.Target = Target;
|
this.Target = Target;
|
||||||
this.Size = Size;
|
this.Size = Size;
|
||||||
|
@ -20,14 +20,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
GL.BindBuffer(Target, Handle);
|
GL.BindBuffer(Target, Handle);
|
||||||
|
|
||||||
GL.BufferData(Target, Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
|
GL.BufferData(Target, (IntPtr)Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetData(int Size, IntPtr HostAddress)
|
public void SetData(long Size, IntPtr HostAddress)
|
||||||
{
|
{
|
||||||
GL.BindBuffer(Target, Handle);
|
GL.BindBuffer(Target, Handle);
|
||||||
|
|
||||||
GL.BufferSubData(Target, IntPtr.Zero, Size, HostAddress);
|
GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Size, HostAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
private List<long>[] UploadedKeys;
|
private List<long>[] UploadedKeys;
|
||||||
|
|
||||||
|
private bool ConstBufferBindingsChanged;
|
||||||
|
|
||||||
public NvGpuEngine3d(NvGpu Gpu)
|
public NvGpuEngine3d(NvGpu Gpu)
|
||||||
{
|
{
|
||||||
this.Gpu = Gpu;
|
this.Gpu = Gpu;
|
||||||
|
@ -90,7 +92,14 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
Gpu.Renderer.Shader.BindProgram();
|
Gpu.Renderer.Shader.BindProgram();
|
||||||
|
|
||||||
//Note: Uncomment SetFrontFace SetCullFace when flipping issues are solved
|
if (ConstBufferBindingsChanged)
|
||||||
|
{
|
||||||
|
ConstBufferBindingsChanged = false;
|
||||||
|
|
||||||
|
Gpu.Renderer.Shader.BindConstBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
||||||
//SetFrontFace();
|
//SetFrontFace();
|
||||||
//SetCullFace();
|
//SetCullFace();
|
||||||
SetDepth();
|
SetDepth();
|
||||||
|
@ -99,7 +108,7 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
SetPrimitiveRestart();
|
SetPrimitiveRestart();
|
||||||
|
|
||||||
UploadTextures(Vmm, Keys);
|
UploadTextures(Vmm, Keys);
|
||||||
UploadUniforms(Vmm);
|
UploadConstBuffers(Vmm);
|
||||||
UploadVertexArrays(Vmm);
|
UploadVertexArrays(Vmm);
|
||||||
|
|
||||||
UnlockCaches();
|
UnlockCaches();
|
||||||
|
@ -107,12 +116,14 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
private void LockCaches()
|
private void LockCaches()
|
||||||
{
|
{
|
||||||
|
Gpu.Renderer.Buffer.LockCache();
|
||||||
Gpu.Renderer.Rasterizer.LockCaches();
|
Gpu.Renderer.Rasterizer.LockCaches();
|
||||||
Gpu.Renderer.Texture.LockCache();
|
Gpu.Renderer.Texture.LockCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnlockCaches()
|
private void UnlockCaches()
|
||||||
{
|
{
|
||||||
|
Gpu.Renderer.Buffer.UnlockCache();
|
||||||
Gpu.Renderer.Rasterizer.UnlockCaches();
|
Gpu.Renderer.Rasterizer.UnlockCaches();
|
||||||
Gpu.Renderer.Texture.UnlockCache();
|
Gpu.Renderer.Texture.UnlockCache();
|
||||||
}
|
}
|
||||||
|
@ -546,32 +557,24 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
Gpu.Renderer.Texture.SetSampler(Sampler);
|
Gpu.Renderer.Texture.SetSampler(Sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UploadUniforms(NvGpuVmm Vmm)
|
private void UploadConstBuffers(NvGpuVmm Vmm)
|
||||||
{
|
{
|
||||||
long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
|
for (int Stage = 0; Stage < 5; Stage++)
|
||||||
|
|
||||||
for (int Index = 0; Index < 5; Index++)
|
|
||||||
{
|
{
|
||||||
int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + (Index + 1) * 0x10);
|
for (int Index = 0; Index < 18; Index++)
|
||||||
int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + (Index + 1) * 0x10);
|
|
||||||
|
|
||||||
//Note: Vertex Program (B) is always enabled.
|
|
||||||
bool Enable = (Control & 1) != 0 || Index == 0;
|
|
||||||
|
|
||||||
if (!Enable)
|
|
||||||
{
|
{
|
||||||
continue;
|
ConstBuffer Cb = ConstBuffers[Stage][Index];
|
||||||
}
|
|
||||||
|
|
||||||
for (int Cbuf = 0; Cbuf < ConstBuffers[Index].Length; Cbuf++)
|
|
||||||
{
|
|
||||||
ConstBuffer Cb = ConstBuffers[Index][Cbuf];
|
|
||||||
|
|
||||||
if (Cb.Enabled)
|
if (Cb.Enabled)
|
||||||
{
|
{
|
||||||
IntPtr DataAddress = Vmm.GetHostAddress(Cb.Position, Cb.Size);
|
long Key = Cb.Position;
|
||||||
|
|
||||||
Gpu.Renderer.Shader.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Cb.Size, DataAddress);
|
if (QueryKeyUpload(Vmm, Key, Cb.Size, NvGpuBufferType.ConstBuffer))
|
||||||
|
{
|
||||||
|
IntPtr Source = Vmm.GetHostAddress(Key, Cb.Size);
|
||||||
|
|
||||||
|
Gpu.Renderer.Buffer.SetData(Key, Cb.Size, Source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -741,10 +744,25 @@ namespace Ryujinx.HLE.Gpu.Engines
|
||||||
|
|
||||||
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress);
|
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress);
|
||||||
|
|
||||||
ConstBuffers[Stage][Index].Position = Position;
|
int Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize);
|
||||||
ConstBuffers[Stage][Index].Enabled = Enabled;
|
|
||||||
|
|
||||||
ConstBuffers[Stage][Index].Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize);
|
if (!Gpu.Renderer.Buffer.IsCached(Position, Size))
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Buffer.Create(Position, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstBuffer Cb = ConstBuffers[Stage][Index];
|
||||||
|
|
||||||
|
if (Cb.Position != Position || Cb.Enabled != Enabled || Cb.Size != Size)
|
||||||
|
{
|
||||||
|
Gpu.Renderer.Buffer.Bind((GalShaderType)Stage, Index, Enabled ? Position : 0);
|
||||||
|
|
||||||
|
ConstBufferBindingsChanged = true;
|
||||||
|
|
||||||
|
ConstBuffers[Stage][Index].Position = Position;
|
||||||
|
ConstBuffers[Stage][Index].Enabled = Enabled;
|
||||||
|
ConstBuffers[Stage][Index].Size = Size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float GetFlipSign(NvGpuEngine3dReg Reg)
|
private float GetFlipSign(NvGpuEngine3dReg Reg)
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace Ryujinx.HLE.Gpu.Memory
|
||||||
Index,
|
Index,
|
||||||
Vertex,
|
Vertex,
|
||||||
Texture,
|
Texture,
|
||||||
|
ConstBuffer,
|
||||||
Count
|
Count
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue