Send data to OpenGL host without client-side copies (#285)

* Directly send host address to buffer data

* Cleanup OGLShader

* Directly copy vertex and index data too

* Revert shader bind "cache"

* Address feedback
This commit is contained in:
ReinUsesLisp 2018-07-19 16:02:51 -03:00 committed by gdkchan
parent 45bb24dbae
commit 5fe0bc584b
8 changed files with 55 additions and 110 deletions

View file

@ -204,6 +204,13 @@ namespace ChocolArm64.Memory
return Modified; return Modified;
} }
public IntPtr GetHostAddress(long Position, long Size)
{
EnsureRangeIsValid(Position, Size, AMemoryPerm.Read);
return (IntPtr)(RamPtr + (ulong)Position);
}
public sbyte ReadSByte(long Position) public sbyte ReadSByte(long Position)
{ {
return (sbyte)ReadByte(Position); return (sbyte)ReadByte(Position);

View file

@ -1,3 +1,5 @@
using System;
namespace Ryujinx.Graphics.Gal namespace Ryujinx.Graphics.Gal
{ {
public interface IGalRasterizer public interface IGalRasterizer
@ -45,9 +47,9 @@ namespace Ryujinx.Graphics.Gal
void SetPrimitiveRestartIndex(uint Index); void SetPrimitiveRestartIndex(uint Index);
void CreateVbo(long Key, byte[] Buffer); void CreateVbo(long Key, int DataSize, IntPtr HostAddress);
void CreateIbo(long Key, byte[] Buffer); void CreateIbo(long Key, int DataSize, IntPtr HostAddress);
void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs); void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs);

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal namespace Ryujinx.Graphics.Gal
@ -10,7 +11,7 @@ namespace Ryujinx.Graphics.Gal
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key); IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key);
void SetConstBuffer(long Key, int Cbuf, byte[] Data); void SetConstBuffer(long Key, int Cbuf, int DataSize, IntPtr HostAddress);
void EnsureTextureBinding(string UniformName, int Value); void EnsureTextureBinding(string UniformName, int Value);

View file

@ -211,28 +211,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.PrimitiveRestartIndex(Index); GL.PrimitiveRestartIndex(Index);
} }
public void CreateVbo(long Key, byte[] Buffer) public void CreateVbo(long Key, int DataSize, IntPtr HostAddress)
{ {
int Handle = GL.GenBuffer(); int Handle = GL.GenBuffer();
VboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length); VboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
IntPtr Length = new IntPtr(Buffer.Length); IntPtr Length = new IntPtr(DataSize);
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle); GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); GL.BufferData(BufferTarget.ArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
} }
public void CreateIbo(long Key, byte[] Buffer) public void CreateIbo(long Key, int DataSize, IntPtr HostAddress)
{ {
int Handle = GL.GenBuffer(); int Handle = GL.GenBuffer();
IboCache.AddOrUpdate(Key, Handle, (uint)Buffer.Length); IboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
IntPtr Length = new IntPtr(Buffer.Length); IntPtr Length = new IntPtr(DataSize);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle); GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
} }
public void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs) public void SetVertexArray(int Stride, long VboKey, GalVertexAttrib[] Attribs)

View file

@ -5,6 +5,8 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Buffer = System.Buffer;
namespace Ryujinx.Graphics.Gal.OpenGL namespace Ryujinx.Graphics.Gal.OpenGL
{ {
public class OGLShader : IGalShader public class OGLShader : IGalShader
@ -151,7 +153,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return Enumerable.Empty<ShaderDeclInfo>(); return Enumerable.Empty<ShaderDeclInfo>();
} }
public void SetConstBuffer(long Key, int Cbuf, byte[] Data) public void SetConstBuffer(long Key, int Cbuf, int DataSize, IntPtr HostAddress)
{ {
if (Stages.TryGetValue(Key, out ShaderStage Stage)) if (Stages.TryGetValue(Key, out ShaderStage Stage))
{ {
@ -159,13 +161,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
OGLStreamBuffer Buffer = GetConstBuffer(Stage.Type, Cbuf); OGLStreamBuffer Buffer = GetConstBuffer(Stage.Type, Cbuf);
int Size = Math.Min(Data.Length, Buffer.Size); int Size = Math.Min(DataSize, Buffer.Size);
byte[] Destiny = Buffer.Map(Size); Buffer.SetData(Size, HostAddress);
Array.Copy(Data, Destiny, Size);
Buffer.Unmap(Size);
} }
} }
} }
@ -278,7 +276,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
int FreeBinding = 0; int FreeBinding = 0;
int BindUniformBlocksIfNotNull(ShaderStage Stage) void BindUniformBlocksIfNotNull(ShaderStage Stage)
{ {
if (Stage != null) if (Stage != null)
{ {
@ -297,8 +295,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
FreeBinding++; FreeBinding++;
} }
} }
return FreeBinding;
} }
BindUniformBlocksIfNotNull(Current.Vertex); BindUniformBlocksIfNotNull(Current.Vertex);
@ -312,7 +308,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
int FreeBinding = 0; int FreeBinding = 0;
int BindUniformBuffersIfNotNull(ShaderStage Stage) void BindUniformBuffersIfNotNull(ShaderStage Stage)
{ {
if (Stage != null) if (Stage != null)
{ {
@ -325,8 +321,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
FreeBinding++; FreeBinding++;
} }
} }
return FreeBinding;
} }
BindUniformBuffersIfNotNull(Current.Vertex); BindUniformBuffersIfNotNull(Current.Vertex);
@ -347,7 +341,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
//Allocate a maximum of 64 KiB //Allocate a maximum of 64 KiB
int Size = Math.Min(GL.GetInteger(GetPName.MaxUniformBlockSize), 64 * 1024); int Size = Math.Min(GL.GetInteger(GetPName.MaxUniformBlockSize), 64 * 1024);
Buffer = OGLStreamBuffer.Create(BufferTarget.UniformBuffer, Size); Buffer = new OGLStreamBuffer(BufferTarget.UniformBuffer, Size);
ConstBuffers[StageIndex][Cbuf] = Buffer; ConstBuffers[StageIndex][Cbuf] = Buffer;
} }

View file

@ -1,9 +1,9 @@
using System;
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using System;
namespace Ryujinx.Graphics.Gal.OpenGL namespace Ryujinx.Graphics.Gal.OpenGL
{ {
abstract class OGLStreamBuffer : IDisposable class OGLStreamBuffer : IDisposable
{ {
public int Handle { get; protected set; } public int Handle { get; protected set; }
@ -11,53 +11,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
protected BufferTarget Target { get; private set; } protected BufferTarget Target { get; private set; }
private bool Mapped = false; public OGLStreamBuffer(BufferTarget Target, int Size)
public OGLStreamBuffer(BufferTarget Target, int MaxSize)
{ {
Handle = 0;
Mapped = false;
this.Target = Target; this.Target = Target;
this.Size = MaxSize; this.Size = Size;
Handle = GL.GenBuffer();
GL.BindBuffer(Target, Handle);
GL.BufferData(Target, Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
} }
public static OGLStreamBuffer Create(BufferTarget Target, int MaxSize) public void SetData(int Size, IntPtr HostAddress)
{ {
//TODO: Query here for ARB_buffer_storage and use when available GL.BindBuffer(Target, Handle);
return new SubDataBuffer(Target, MaxSize);
GL.BufferSubData(Target, IntPtr.Zero, Size, HostAddress);
} }
public byte[] Map(int Size)
{
if (Handle == 0 || Mapped || Size > this.Size)
{
throw new InvalidOperationException();
}
byte[] Memory = InternMap(Size);
Mapped = true;
return Memory;
}
public void Unmap(int UsedSize)
{
if (Handle == 0 || !Mapped)
{
throw new InvalidOperationException();
}
InternUnmap(UsedSize);
Mapped = false;
}
protected abstract byte[] InternMap(int Size);
protected abstract void InternUnmap(int UsedSize);
public void Dispose() public void Dispose()
{ {
Dispose(true); Dispose(true);
@ -73,41 +45,4 @@ namespace Ryujinx.Graphics.Gal.OpenGL
} }
} }
} }
class SubDataBuffer : OGLStreamBuffer
{
private byte[] Memory;
public SubDataBuffer(BufferTarget Target, int MaxSize)
: base(Target, MaxSize)
{
Memory = new byte[MaxSize];
GL.GenBuffers(1, out int Handle);
GL.BindBuffer(Target, Handle);
GL.BufferData(Target, Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
this.Handle = Handle;
}
protected override byte[] InternMap(int Size)
{
return Memory;
}
protected override void InternUnmap(int UsedSize)
{
GL.BindBuffer(Target, Handle);
unsafe
{
fixed (byte* MemoryPtr = Memory)
{
GL.BufferSubData(Target, IntPtr.Zero, UsedSize, (IntPtr)MemoryPtr);
}
}
}
}
} }

View file

@ -560,9 +560,9 @@ namespace Ryujinx.HLE.Gpu.Engines
if (Cb.Enabled) if (Cb.Enabled)
{ {
byte[] Data = Vmm.ReadBytes(Cb.Position, (uint)Cb.Size); IntPtr DataAddress = Vmm.GetHostAddress(Cb.Position, Cb.Size);
Gpu.Renderer.Shader.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Data); Gpu.Renderer.Shader.SetConstBuffer(BasePosition + (uint)Offset, Cbuf, Cb.Size, DataAddress);
} }
} }
} }
@ -595,9 +595,9 @@ namespace Ryujinx.HLE.Gpu.Engines
if (!IboCached || Vmm.IsRegionModified(IboKey, (uint)IbSize, NvGpuBufferType.Index)) if (!IboCached || Vmm.IsRegionModified(IboKey, (uint)IbSize, NvGpuBufferType.Index))
{ {
byte[] Data = Vmm.ReadBytes(IndexPosition, (uint)IbSize); IntPtr DataAddress = Vmm.GetHostAddress(IndexPosition, IbSize);
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, Data); Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, DataAddress);
} }
Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat); Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat);
@ -659,9 +659,9 @@ namespace Ryujinx.HLE.Gpu.Engines
if (!VboCached || Vmm.IsRegionModified(VboKey, VbSize, NvGpuBufferType.Vertex)) if (!VboCached || Vmm.IsRegionModified(VboKey, VbSize, NvGpuBufferType.Vertex))
{ {
byte[] Data = Vmm.ReadBytes(VertexPosition, VbSize); IntPtr DataAddress = Vmm.GetHostAddress(VertexPosition, VbSize);
Gpu.Renderer.Rasterizer.CreateVbo(VboKey, Data); Gpu.Renderer.Rasterizer.CreateVbo(VboKey, (int)VbSize, DataAddress);
} }
Gpu.Renderer.Rasterizer.SetVertexArray(Stride, VboKey, Attribs[Index].ToArray()); Gpu.Renderer.Rasterizer.SetVertexArray(Stride, VboKey, Attribs[Index].ToArray());

View file

@ -1,5 +1,6 @@
using ChocolArm64.Memory; using ChocolArm64.Memory;
using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Gal;
using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
namespace Ryujinx.HLE.Gpu.Memory namespace Ryujinx.HLE.Gpu.Memory
@ -279,6 +280,11 @@ namespace Ryujinx.HLE.Gpu.Memory
return Cache.IsRegionModified(Memory, BufferType, PA, Size); return Cache.IsRegionModified(Memory, BufferType, PA, Size);
} }
public IntPtr GetHostAddress(long Position, long Size)
{
return Memory.GetHostAddress(GetPhysicalAddress(Position), Size);
}
public byte ReadByte(long Position) public byte ReadByte(long Position)
{ {
Position = GetPhysicalAddress(Position); Position = GetPhysicalAddress(Position);