Spanify Graphics Abstraction Layer (#1226)

* Spanify Graphics Abstraction Layer

* Be explicit about BufferHandle size
This commit is contained in:
gdkchan 2020-05-23 06:46:09 -03:00 committed by GitHub
parent cc8dbdd3fb
commit 5011640b30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 208 additions and 134 deletions

View file

@ -0,0 +1,22 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL
{
[StructLayout(LayoutKind.Sequential, Size = 8)]
public struct BufferHandle : IEquatable<BufferHandle>
{
private readonly ulong _value;
public static BufferHandle Null => new BufferHandle(0);
private BufferHandle(ulong value) => _value = value;
public override bool Equals(object obj) => obj is BufferHandle handle && Equals(handle);
public bool Equals([AllowNull] BufferHandle other) => other._value == _value;
public override int GetHashCode() => _value.GetHashCode();
public static bool operator ==(BufferHandle left, BufferHandle right) => left.Equals(right);
public static bool operator !=(BufferHandle left, BufferHandle right) => !(left == right);
}
}

View file

@ -2,18 +2,18 @@ namespace Ryujinx.Graphics.GAL
{ {
public struct BufferRange public struct BufferRange
{ {
private static BufferRange _empty = new BufferRange(null, 0, 0); private static readonly BufferRange _empty = new BufferRange(BufferHandle.Null, 0, 0);
public BufferRange Empty => _empty; public BufferRange Empty => _empty;
public IBuffer Buffer { get; } public BufferHandle Handle { get; }
public int Offset { get; } public int Offset { get; }
public int Size { get; } public int Size { get; }
public BufferRange(IBuffer buffer, int offset, int size) public BufferRange(BufferHandle handle, int offset, int size)
{ {
Buffer = buffer; Handle = handle;
Offset = offset; Offset = offset;
Size = size; Size = size;
} }

View file

@ -1,15 +0,0 @@
using System;
namespace Ryujinx.Graphics.GAL
{
public interface IBuffer : IDisposable
{
void CopyTo(IBuffer destination, int srcOffset, int dstOffset, int size);
byte[] GetData(int offset, int size);
void SetData(ReadOnlySpan<byte> data);
void SetData(int offset, ReadOnlySpan<byte> data);
}
}

View file

@ -1,4 +1,5 @@
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -14,6 +15,8 @@ namespace Ryujinx.Graphics.GAL
int stencilValue, int stencilValue,
int stencilMask); int stencilMask);
void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size);
void DispatchCompute(int groupsX, int groupsY, int groupsZ); void DispatchCompute(int groupsX, int groupsY, int groupsZ);
void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance); void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance);
@ -49,7 +52,7 @@ namespace Ryujinx.Graphics.GAL
void SetRasterizerDiscard(bool discard); void SetRasterizerDiscard(bool discard);
void SetRenderTargetColorMasks(uint[] componentMask); void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
void SetRenderTargets(ITexture[] colors, ITexture depthStencil); void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
@ -68,10 +71,10 @@ namespace Ryujinx.Graphics.GAL
void SetUserClipDistance(int index, bool enableClip); void SetUserClipDistance(int index, bool enableClip);
void SetVertexAttribs(VertexAttribDescriptor[] vertexAttribs); void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
void SetVertexBuffers(VertexBufferDescriptor[] vertexBuffers); void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
void SetViewports(int first, Viewport[] viewports); void SetViewports(int first, ReadOnlySpan<Viewport> viewports);
void TextureBarrier(); void TextureBarrier();
void TextureBarrierTiled(); void TextureBarrierTiled();

View file

@ -11,15 +11,21 @@ namespace Ryujinx.Graphics.GAL
IShader CompileShader(ShaderProgram shader); IShader CompileShader(ShaderProgram shader);
IBuffer CreateBuffer(int size); BufferHandle CreateBuffer(int size);
IProgram CreateProgram(IShader[] shaders); IProgram CreateProgram(IShader[] shaders);
ISampler CreateSampler(SamplerCreateInfo info); ISampler CreateSampler(SamplerCreateInfo info);
ITexture CreateTexture(TextureCreateInfo info); ITexture CreateTexture(TextureCreateInfo info);
void DeleteBuffer(BufferHandle buffer);
byte[] GetBufferData(BufferHandle buffer, int offset, int size);
Capabilities GetCapabilities(); Capabilities GetCapabilities();
void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);
void UpdateCounters(); void UpdateCounters();
ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler); ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler);

View file

@ -45,6 +45,11 @@ namespace Ryujinx.Graphics.Gpu
/// </summary> /// </summary>
public const int ShaderStages = 5; public const int ShaderStages = 5;
/// <summary>
/// Maximum number of vertex attributes.
/// </summary>
public const int TotalVertexAttribs = 16;
/// <summary> /// <summary>
/// Maximum number of vertex buffers. /// Maximum number of vertex buffers.
/// </summary> /// </summary>

View file

@ -570,9 +570,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// <param name="state">Current GPU state</param> /// <param name="state">Current GPU state</param>
private void UpdateVertexAttribState(GpuState state) private void UpdateVertexAttribState(GpuState state)
{ {
VertexAttribDescriptor[] vertexAttribs = new VertexAttribDescriptor[16]; Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
for (int index = 0; index < 16; index++) for (int index = 0; index < Constants.TotalVertexAttribs; index++)
{ {
var vertexAttrib = state.Get<VertexAttribState>(MethodOffset.VertexAttribState, index); var vertexAttrib = state.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
@ -660,7 +660,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{ {
_isAnyVbInstanced = false; _isAnyVbInstanced = false;
for (int index = 0; index < 16; index++) for (int index = 0; index < Constants.TotalVertexBuffers; index++)
{ {
var vertexBuffer = state.Get<VertexBufferState>(MethodOffset.VertexBufferState, index); var vertexBuffer = state.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
@ -728,7 +728,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
{ {
bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared); bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared);
uint[] componentMasks = new uint[Constants.TotalRenderTargets]; Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
for (int index = 0; index < Constants.TotalRenderTargets; index++) for (int index = 0; index < Constants.TotalRenderTargets; index++)
{ {

View file

@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly GpuContext _context; private readonly GpuContext _context;
/// <summary> /// <summary>
/// Host buffer object. /// Host buffer handle.
/// </summary> /// </summary>
public IBuffer HostBuffer { get; } public BufferHandle Handle { get; }
/// <summary> /// <summary>
/// Start address of the buffer in guest memory. /// Start address of the buffer in guest memory.
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
Address = address; Address = address;
Size = size; Size = size;
HostBuffer = context.Renderer.CreateBuffer((int)size); Handle = context.Renderer.CreateBuffer((int)size);
_modifiedRanges = new (ulong, ulong)[size / PhysicalMemory.PageSize]; _modifiedRanges = new (ulong, ulong)[size / PhysicalMemory.PageSize];
@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
int offset = (int)(address - Address); int offset = (int)(address - Address);
return new BufferRange(HostBuffer, offset, (int)size); return new BufferRange(Handle, offset, (int)size);
} }
/// <summary> /// <summary>
@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
int offset = (int)(mAddress - Address); int offset = (int)(mAddress - Address);
HostBuffer.SetData(offset, _context.PhysicalMemory.GetSpan(mAddress, (int)mSize)); _context.Renderer.SetBufferData(Handle, offset, _context.PhysicalMemory.GetSpan(mAddress, (int)mSize));
} }
} }
@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="dstOffset">The offset of the destination buffer to copy into</param> /// <param name="dstOffset">The offset of the destination buffer to copy into</param>
public void CopyTo(Buffer destination, int dstOffset) public void CopyTo(Buffer destination, int dstOffset)
{ {
HostBuffer.CopyTo(destination.HostBuffer, 0, dstOffset, (int)Size); _context.Renderer.Pipeline.CopyBuffer(Handle, destination.Handle, 0, dstOffset, (int)Size);
} }
/// <summary> /// <summary>
@ -149,7 +149,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
int offset = (int)(address - Address); int offset = (int)(address - Address);
byte[] data = HostBuffer.GetData(offset, (int)size); byte[] data = _context.Renderer.GetBufferData(Handle, offset, (int)size);
_context.PhysicalMemory.Write(address, data); _context.PhysicalMemory.Write(address, data);
} }
@ -159,7 +159,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public void Dispose() public void Dispose()
{ {
HostBuffer.Dispose(); _context.Renderer.DeleteBuffer(Handle);
} }
} }
} }

View file

@ -477,7 +477,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
{ {
_vertexBuffersDirty = false; _vertexBuffersDirty = false;
VertexBufferDescriptor[] vertexBuffers = new VertexBufferDescriptor[Constants.TotalVertexBuffers]; Span<VertexBufferDescriptor> vertexBuffers = stackalloc VertexBufferDescriptor[Constants.TotalVertexBuffers];
for (int index = 0; (vbEnableMask >> index) != 0; index++) for (int index = 0; (vbEnableMask >> index) != 0; index++)
{ {
@ -666,8 +666,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
int srcOffset = (int)(srcAddress - srcBuffer.Address); int srcOffset = (int)(srcAddress - srcBuffer.Address);
int dstOffset = (int)(dstAddress - dstBuffer.Address); int dstOffset = (int)(dstAddress - dstBuffer.Address);
srcBuffer.HostBuffer.CopyTo( _context.Renderer.Pipeline.CopyBuffer(
dstBuffer.HostBuffer, srcBuffer.Handle,
dstBuffer.Handle,
srcOffset, srcOffset,
dstOffset, dstOffset,
(int)size); (int)size);

View file

@ -4,22 +4,22 @@ using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL
{ {
class Buffer : IBuffer static class Buffer
{ {
public int Handle { get; } public static BufferHandle Create(int size)
public Buffer(int size)
{ {
Handle = GL.GenBuffer(); int handle = GL.GenBuffer();
GL.BindBuffer(BufferTarget.CopyWriteBuffer, Handle); GL.BindBuffer(BufferTarget.CopyWriteBuffer, handle);
GL.BufferData(BufferTarget.CopyWriteBuffer, size, IntPtr.Zero, BufferUsageHint.DynamicDraw); GL.BufferData(BufferTarget.CopyWriteBuffer, size, IntPtr.Zero, BufferUsageHint.DynamicDraw);
return Handle.FromInt32<BufferHandle>(handle);
} }
public void CopyTo(IBuffer destination, int srcOffset, int dstOffset, int size) public static void Copy(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
{ {
GL.BindBuffer(BufferTarget.CopyReadBuffer, Handle); GL.BindBuffer(BufferTarget.CopyReadBuffer, source.ToInt32());
GL.BindBuffer(BufferTarget.CopyWriteBuffer, ((Buffer)destination).Handle); GL.BindBuffer(BufferTarget.CopyWriteBuffer, destination.ToInt32());
GL.CopyBufferSubData( GL.CopyBufferSubData(
BufferTarget.CopyReadBuffer, BufferTarget.CopyReadBuffer,
@ -29,9 +29,9 @@ namespace Ryujinx.Graphics.OpenGL
(IntPtr)size); (IntPtr)size);
} }
public byte[] GetData(int offset, int size) public static byte[] GetData(BufferHandle buffer, int offset, int size)
{ {
GL.BindBuffer(BufferTarget.CopyReadBuffer, Handle); GL.BindBuffer(BufferTarget.CopyReadBuffer, buffer.ToInt32());
byte[] data = new byte[size]; byte[] data = new byte[size];
@ -40,22 +40,9 @@ namespace Ryujinx.Graphics.OpenGL
return data; return data;
} }
public void SetData(ReadOnlySpan<byte> data) public static void SetData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
{ {
unsafe GL.BindBuffer(BufferTarget.CopyWriteBuffer, buffer.ToInt32());
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, Handle);
fixed (byte* ptr = data)
{
GL.BufferData(BufferTarget.CopyWriteBuffer, data.Length, (IntPtr)ptr, BufferUsageHint.DynamicDraw);
}
}
}
public void SetData(int offset, ReadOnlySpan<byte> data)
{
GL.BindBuffer(BufferTarget.CopyWriteBuffer, Handle);
unsafe unsafe
{ {
@ -66,9 +53,9 @@ namespace Ryujinx.Graphics.OpenGL
} }
} }
public void Dispose() public static void Delete(BufferHandle buffer)
{ {
GL.DeleteBuffer(Handle); GL.DeleteBuffer(buffer.ToInt32());
} }
} }
} }

View file

@ -0,0 +1,10 @@
namespace Ryujinx.Graphics.OpenGL
{
static class Constants
{
public const int MaxRenderTargets = 8;
public const int MaxViewports = 16;
public const int MaxVertexAttribs = 16;
public const int MaxVertexBuffers = 16;
}
}

View file

@ -1,5 +1,6 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Image;
using System; using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.OpenGL
{
static class Handle
{
public static T FromInt32<T>(int handle) where T : unmanaged
{
Debug.Assert(Unsafe.SizeOf<T>() == sizeof(ulong));
ulong handle64 = (uint)handle;
return Unsafe.As<ulong, T>(ref handle64);
}
public static int ToInt32(this BufferHandle handle)
{
return (int)Unsafe.As<BufferHandle, ulong>(ref handle);
}
}
}

View file

@ -1,7 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
class Sampler : ISampler class Sampler : ISampler
{ {

View file

@ -1,10 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
class TextureBase class TextureBase
{ {

View file

@ -2,14 +2,14 @@
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
class TextureBuffer : TextureBase, ITexture class TextureBuffer : TextureBase, ITexture
{ {
private int _bufferOffset; private int _bufferOffset;
private int _bufferSize; private int _bufferSize;
private Buffer _buffer; private BufferHandle _buffer;
public TextureBuffer(TextureCreateInfo info) : base(info) {} public TextureBuffer(TextureCreateInfo info) : base(info) {}
@ -30,24 +30,24 @@ namespace Ryujinx.Graphics.OpenGL
public byte[] GetData() public byte[] GetData()
{ {
return _buffer?.GetData(_bufferOffset, _bufferSize); return Buffer.GetData(_buffer, _bufferOffset, _bufferSize);
} }
public void SetData(ReadOnlySpan<byte> data) public void SetData(ReadOnlySpan<byte> data)
{ {
_buffer?.SetData(_bufferOffset, data.Slice(0, Math.Min(data.Length, _bufferSize))); Buffer.SetData(_buffer, _bufferOffset, data.Slice(0, Math.Min(data.Length, _bufferSize)));
} }
public void SetStorage(BufferRange buffer) public void SetStorage(BufferRange buffer)
{ {
if (buffer.Buffer == _buffer && if (buffer.Handle == _buffer &&
buffer.Offset == _bufferOffset && buffer.Offset == _bufferOffset &&
buffer.Size == _bufferSize) buffer.Size == _bufferSize)
{ {
return; return;
} }
_buffer = (Buffer)buffer.Buffer; _buffer = buffer.Handle;
_bufferOffset = buffer.Offset; _bufferOffset = buffer.Offset;
_bufferSize = buffer.Size; _bufferSize = buffer.Size;
@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.OpenGL
SizedInternalFormat format = (SizedInternalFormat)FormatTable.GetFormatInfo(Info.Format).PixelInternalFormat; SizedInternalFormat format = (SizedInternalFormat)FormatTable.GetFormatInfo(Info.Format).PixelInternalFormat;
GL.TexBufferRange(TextureBufferTarget.TextureBuffer, format, _buffer.Handle, (IntPtr)buffer.Offset, buffer.Size); GL.TexBufferRange(TextureBufferTarget.TextureBuffer, format, _buffer.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
} }
public void Dispose() public void Dispose()

View file

@ -2,7 +2,7 @@ using Ryujinx.Graphics.GAL;
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using System; using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
class TextureCopy : IDisposable class TextureCopy : IDisposable
{ {

View file

@ -3,7 +3,7 @@ using Ryujinx.Common;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
static class TextureCopyUnscaled static class TextureCopyUnscaled
{ {

View file

@ -2,7 +2,7 @@ using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
class TextureStorage class TextureStorage
{ {

View file

@ -2,7 +2,7 @@ using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL.Image
{ {
class TextureView : TextureBase, ITexture class TextureView : TextureBase, ITexture
{ {

View file

@ -1,6 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Image;
using Ryujinx.Graphics.OpenGL.Queries; using Ryujinx.Graphics.OpenGL.Queries;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using System; using System;
@ -32,7 +33,7 @@ namespace Ryujinx.Graphics.OpenGL
private ClipOrigin _clipOrigin; private ClipOrigin _clipOrigin;
private ClipDepthMode _clipDepthMode; private ClipDepthMode _clipDepthMode;
private uint[] _componentMasks; private readonly uint[] _componentMasks;
private bool _scissor0Enable = false; private bool _scissor0Enable = false;
@ -43,6 +44,13 @@ namespace Ryujinx.Graphics.OpenGL
_rasterizerDiscard = false; _rasterizerDiscard = false;
_clipOrigin = ClipOrigin.LowerLeft; _clipOrigin = ClipOrigin.LowerLeft;
_clipDepthMode = ClipDepthMode.NegativeOneToOne; _clipDepthMode = ClipDepthMode.NegativeOneToOne;
_componentMasks = new uint[Constants.MaxRenderTargets];
for (int index = 0; index < Constants.MaxRenderTargets; index++)
{
_componentMasks[index] = 0xf;
}
} }
public void Barrier() public void Barrier()
@ -112,6 +120,11 @@ namespace Ryujinx.Graphics.OpenGL
_framebuffer.SignalModified(); _framebuffer.SignalModified();
} }
public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
{
Buffer.Copy(source, destination, srcOffset, dstOffset, size);
}
public void DispatchCompute(int groupsX, int groupsY, int groupsZ) public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{ {
if (!_program.IsLinked) if (!_program.IsLinked)
@ -631,7 +644,7 @@ namespace Ryujinx.Graphics.OpenGL
EnsureVertexArray(); EnsureVertexArray();
_vertexArray.SetIndexBuffer((Buffer)buffer.Buffer); _vertexArray.SetIndexBuffer(buffer.Handle);
} }
public void SetPointSize(float size) public void SetPointSize(float size)
@ -661,7 +674,6 @@ namespace Ryujinx.Graphics.OpenGL
public void SetProgram(IProgram program) public void SetProgram(IProgram program)
{ {
_program = (Program)program; _program = (Program)program;
_program.Bind(); _program.Bind();
} }
@ -679,12 +691,12 @@ namespace Ryujinx.Graphics.OpenGL
_rasterizerDiscard = discard; _rasterizerDiscard = discard;
} }
public void SetRenderTargetColorMasks(uint[] componentMasks) public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
{ {
_componentMasks = (uint[])componentMasks.Clone();
for (int index = 0; index < componentMasks.Length; index++) for (int index = 0; index < componentMasks.Length; index++)
{ {
_componentMasks[index] = componentMasks[index];
RestoreComponentMask(index); RestoreComponentMask(index);
} }
} }
@ -823,21 +835,21 @@ namespace Ryujinx.Graphics.OpenGL
GL.Enable(EnableCap.ClipDistance0 + index); GL.Enable(EnableCap.ClipDistance0 + index);
} }
public void SetVertexAttribs(VertexAttribDescriptor[] vertexAttribs) public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
{ {
EnsureVertexArray(); EnsureVertexArray();
_vertexArray.SetVertexAttributes(vertexAttribs); _vertexArray.SetVertexAttributes(vertexAttribs);
} }
public void SetVertexBuffers(VertexBufferDescriptor[] vertexBuffers) public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
{ {
EnsureVertexArray(); EnsureVertexArray();
_vertexArray.SetVertexBuffers(vertexBuffers); _vertexArray.SetVertexBuffers(vertexBuffers);
} }
public void SetViewports(int first, Viewport[] viewports) public void SetViewports(int first, ReadOnlySpan<Viewport> viewports)
{ {
bool flipY = false; bool flipY = false;
@ -906,18 +918,16 @@ namespace Ryujinx.Graphics.OpenGL
? BufferRangeTarget.ShaderStorageBuffer ? BufferRangeTarget.ShaderStorageBuffer
: BufferRangeTarget.UniformBuffer; : BufferRangeTarget.UniformBuffer;
if (buffer.Buffer == null) if (buffer.Handle == null)
{ {
GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0); GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
return; return;
} }
int bufferHandle = ((Buffer)buffer.Buffer).Handle;
IntPtr bufferOffset = (IntPtr)buffer.Offset; IntPtr bufferOffset = (IntPtr)buffer.Offset;
GL.BindBufferRange(target, bindingPoint, bufferHandle, bufferOffset, buffer.Size); GL.BindBufferRange(target, bindingPoint, buffer.Handle.ToInt32(), bufferOffset, buffer.Size);
} }
private void SetOrigin(ClipOrigin origin) private void SetOrigin(ClipOrigin origin)
@ -997,15 +1007,12 @@ namespace Ryujinx.Graphics.OpenGL
private void RestoreComponentMask(int index) private void RestoreComponentMask(int index)
{ {
if (_componentMasks != null) GL.ColorMask(
{ index,
GL.ColorMask( (_componentMasks[index] & 1u) != 0,
index, (_componentMasks[index] & 2u) != 0,
(_componentMasks[index] & 1u) != 0, (_componentMasks[index] & 4u) != 0,
(_componentMasks[index] & 2u) != 0, (_componentMasks[index] & 8u) != 0);
(_componentMasks[index] & 4u) != 0,
(_componentMasks[index] & 8u) != 0);
}
} }
public void RestoreScissor0Enable() public void RestoreScissor0Enable()

View file

@ -1,6 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Image;
using Ryujinx.Graphics.OpenGL.Queries; using Ryujinx.Graphics.OpenGL.Queries;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using System; using System;
@ -38,9 +39,9 @@ namespace Ryujinx.Graphics.OpenGL
return new Shader(shader); return new Shader(shader);
} }
public IBuffer CreateBuffer(int size) public BufferHandle CreateBuffer(int size)
{ {
return new Buffer(size); return Buffer.Create(size);
} }
public IProgram CreateProgram(IShader[] shaders) public IProgram CreateProgram(IShader[] shaders)
@ -58,6 +59,16 @@ namespace Ryujinx.Graphics.OpenGL
return info.Target == Target.TextureBuffer ? new TextureBuffer(info) : new TextureStorage(this, info).CreateDefaultView(); return info.Target == Target.TextureBuffer ? new TextureBuffer(info) : new TextureStorage(this, info).CreateDefaultView();
} }
public void DeleteBuffer(BufferHandle buffer)
{
Buffer.Delete(buffer);
}
public byte[] GetBufferData(BufferHandle buffer, int offset, int size)
{
return Buffer.GetData(buffer, offset, size);
}
public Capabilities GetCapabilities() public Capabilities GetCapabilities()
{ {
return new Capabilities( return new Capabilities(
@ -68,6 +79,11 @@ namespace Ryujinx.Graphics.OpenGL
HwCapabilities.MaxSupportedAnisotropy); HwCapabilities.MaxSupportedAnisotropy);
} }
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
{
Buffer.SetData(buffer, offset, data);
}
public void UpdateCounters() public void UpdateCounters()
{ {
_counters.Update(); _counters.Update();

View file

@ -10,12 +10,18 @@ namespace Ryujinx.Graphics.OpenGL
private bool _needsAttribsUpdate; private bool _needsAttribsUpdate;
private VertexBufferDescriptor[] _vertexBuffers; private readonly VertexAttribDescriptor[] _vertexAttribs;
private VertexAttribDescriptor[] _vertexAttribs; private readonly VertexBufferDescriptor[] _vertexBuffers;
private int _vertexAttribsCount;
private int _vertexBuffersCount;
public VertexArray() public VertexArray()
{ {
Handle = GL.GenVertexArray(); Handle = GL.GenVertexArray();
_vertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttribs];
_vertexBuffers = new VertexBufferDescriptor[Constants.MaxVertexBuffers];
} }
public void Bind() public void Bind()
@ -23,17 +29,17 @@ namespace Ryujinx.Graphics.OpenGL
GL.BindVertexArray(Handle); GL.BindVertexArray(Handle);
} }
public void SetVertexBuffers(VertexBufferDescriptor[] vertexBuffers) public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
{ {
int bindingIndex = 0; int bindingIndex = 0;
foreach (VertexBufferDescriptor vb in vertexBuffers) for (int index = 0; index < vertexBuffers.Length; index++)
{ {
if (vb.Buffer.Buffer != null) VertexBufferDescriptor vb = vertexBuffers[index];
{
int bufferHandle = ((Buffer)vb.Buffer.Buffer).Handle;
GL.BindVertexBuffer(bindingIndex, bufferHandle, (IntPtr)vb.Buffer.Offset, vb.Stride); if (vb.Buffer.Handle != null)
{
GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride);
GL.VertexBindingDivisor(bindingIndex, vb.Divisor); GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
} }
@ -42,31 +48,35 @@ namespace Ryujinx.Graphics.OpenGL
GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0); GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0);
} }
_vertexBuffers[index] = vb;
bindingIndex++; bindingIndex++;
} }
_vertexBuffers = vertexBuffers; _vertexBuffersCount = bindingIndex;
_needsAttribsUpdate = true; _needsAttribsUpdate = true;
} }
public void SetVertexAttributes(VertexAttribDescriptor[] vertexAttribs) public void SetVertexAttributes(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
{ {
int attribIndex = 0; int index = 0;
foreach (VertexAttribDescriptor attrib in vertexAttribs) for (; index < vertexAttribs.Length; index++)
{ {
VertexAttribDescriptor attrib = vertexAttribs[index];
FormatInfo fmtInfo = FormatTable.GetFormatInfo(attrib.Format); FormatInfo fmtInfo = FormatTable.GetFormatInfo(attrib.Format);
if (attrib.IsZero) if (attrib.IsZero)
{ {
// Disabling the attribute causes the shader to read a constant value. // Disabling the attribute causes the shader to read a constant value.
// The value is configurable, but by default is a vector of (0, 0, 0, 1). // The value is configurable, but by default is a vector of (0, 0, 0, 1).
GL.DisableVertexAttribArray(attribIndex); GL.DisableVertexAttribArray(index);
} }
else else
{ {
GL.EnableVertexAttribArray(attribIndex); GL.EnableVertexAttribArray(index);
} }
int offset = attrib.Offset; int offset = attrib.Offset;
@ -79,47 +89,47 @@ namespace Ryujinx.Graphics.OpenGL
{ {
VertexAttribType type = (VertexAttribType)fmtInfo.PixelType; VertexAttribType type = (VertexAttribType)fmtInfo.PixelType;
GL.VertexAttribFormat(attribIndex, size, type, fmtInfo.Normalized, offset); GL.VertexAttribFormat(index, size, type, fmtInfo.Normalized, offset);
} }
else else
{ {
VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType; VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType;
GL.VertexAttribIFormat(attribIndex, size, type, offset); GL.VertexAttribIFormat(index, size, type, offset);
} }
GL.VertexAttribBinding(attribIndex, attrib.BufferIndex); GL.VertexAttribBinding(index, attrib.BufferIndex);
attribIndex++; _vertexAttribs[index] = attrib;
} }
for (; attribIndex < 16; attribIndex++) _vertexAttribsCount = index;
for (; index < Constants.MaxVertexAttribs; index++)
{ {
GL.DisableVertexAttribArray(attribIndex); GL.DisableVertexAttribArray(index);
} }
_vertexAttribs = vertexAttribs;
} }
public void SetIndexBuffer(Buffer indexBuffer) public void SetIndexBuffer(BufferHandle buffer)
{ {
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer?.Handle ?? 0); GL.BindBuffer(BufferTarget.ElementArrayBuffer, buffer.ToInt32());
} }
public void Validate() public void Validate()
{ {
for (int attribIndex = 0; attribIndex < _vertexAttribs.Length; attribIndex++) for (int attribIndex = 0; attribIndex < _vertexAttribsCount; attribIndex++)
{ {
VertexAttribDescriptor attrib = _vertexAttribs[attribIndex]; VertexAttribDescriptor attrib = _vertexAttribs[attribIndex];
if ((uint)attrib.BufferIndex >= _vertexBuffers.Length) if ((uint)attrib.BufferIndex >= _vertexBuffersCount)
{ {
GL.DisableVertexAttribArray(attribIndex); GL.DisableVertexAttribArray(attribIndex);
continue; continue;
} }
if (_vertexBuffers[attrib.BufferIndex].Buffer.Buffer == null) if (_vertexBuffers[attrib.BufferIndex].Buffer.Handle == null)
{ {
GL.DisableVertexAttribArray(attribIndex); GL.DisableVertexAttribArray(attribIndex);

View file

@ -1,5 +1,6 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Image;
using System; using System;
namespace Ryujinx.Graphics.OpenGL namespace Ryujinx.Graphics.OpenGL