mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-11-24 16:04:15 +00:00
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:
parent
45bb24dbae
commit
5fe0bc584b
8 changed files with 55 additions and 110 deletions
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue