From 65abc70edc963d24809b6ec0f0406814cb042ed9 Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Thu, 9 May 2024 16:32:14 -0400 Subject: [PATCH] Almost there --- src/Ryujinx.Graphics.OpenGL/Framebuffer.cs | 2 +- .../PersistentBuffers.cs | 6 +- src/Ryujinx.Graphics.OpenGL/Pipeline.cs | 88 +++++++++---------- src/Ryujinx.Graphics.OpenGL/Program.cs | 2 +- src/Ryujinx.Graphics.OpenGL/VertexArray.cs | 56 ++++++------ src/Ryujinx.Graphics.OpenGL/Window.cs | 7 +- 6 files changed, 82 insertions(+), 79 deletions(-) diff --git a/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs index 7aa720eac..37b9a14cf 100644 --- a/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs +++ b/src/Ryujinx.Graphics.OpenGL/Framebuffer.cs @@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.OpenGL drawBuffers[index] = DrawBufferMode.ColorAttachment0 + index; } - api.DrawBuffers(colorsCount, drawBuffers); + api.DrawBuffers((uint)colorsCount, drawBuffers); } private static FramebufferAttachment GetAttachment(Format format) diff --git a/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs b/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs index 978263ce7..3ba8b1e19 100644 --- a/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs +++ b/src/Ryujinx.Graphics.OpenGL/PersistentBuffers.cs @@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.OpenGL public void Map(BufferHandle handle, int size) { - GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToInt32()); + GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToUInt32()); IntPtr ptr = GL.MapBufferRange(BufferTargetARB.CopyWriteBuffer, IntPtr.Zero, size, BufferAccessMask.MapReadBit | BufferAccessMask.MapPersistentBit); _maps[handle] = ptr; @@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.OpenGL { if (_maps.ContainsKey(handle)) { - GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToInt32()); + GL.BindBuffer(BufferTargetARB.CopyWriteBuffer, handle.ToUInt32()); GL.UnmapBuffer(BufferTargetARB.CopyWriteBuffer); _maps.Remove(handle); @@ -93,7 +93,7 @@ namespace Ryujinx.Graphics.OpenGL private static void Sync() { - GL.MemoryBarrier(MemoryBarrierFlags.ClientMappedBufferBarrierBit); + GL.MemoryBarrier(MemoryBarrierMask.ClientMappedBufferBarrierBit); IntPtr sync = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None); WaitSyncStatus syncResult = GL.ClientWaitSync(sync, ClientWaitSyncFlags.SyncFlushCommandsBit, 1000000000); diff --git a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs index a652d8c2c..5af2da645 100644 --- a/src/Ryujinx.Graphics.OpenGL/Pipeline.cs +++ b/src/Ryujinx.Graphics.OpenGL/Pipeline.cs @@ -37,8 +37,8 @@ namespace Ryujinx.Graphics.OpenGL private bool _stencilTestEnable; private bool _cullEnable; - private float[] _viewportArray = Array.Empty(); - private double[] _depthRangeArray = Array.Empty(); + private float[] _viewportArray = []; + private double[] _depthRangeArray = []; private uint _boundDrawFramebuffer; private uint _boundReadFramebuffer; @@ -102,7 +102,7 @@ namespace Ryujinx.Graphics.OpenGL public void ClearBuffer(BufferHandle destination, int offset, int size, uint value) { - Buffer.Clear(_api, destination, offset, size, value); + Buffer.Clear(_api, destination, offset, (uint)size, value); } public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color) @@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.OpenGL EnsureFramebuffer(); _api.ColorMask( - index, + (uint)index, (componentMask & 1) != 0, (componentMask & 2) != 0, (componentMask & 4) != 0, @@ -149,7 +149,7 @@ namespace Ryujinx.Graphics.OpenGL if (stencilMaskChanged) { - _api.StencilMaskSeparate(TriangleFace.Front, stencilMask); + _api.StencilMaskSeparate(TriangleFace.Front, (uint)stencilMask); } if (depthMaskChanged) @@ -175,7 +175,7 @@ namespace Ryujinx.Graphics.OpenGL if (stencilMaskChanged) { - _api.StencilMaskSeparate(TriangleFace.Front, _stencilFrontMask); + _api.StencilMaskSeparate(TriangleFace.Front, (uint)_stencilFrontMask); } if (depthMaskChanged) @@ -184,19 +184,19 @@ namespace Ryujinx.Graphics.OpenGL } } - private static void ClearDepthStencil(GL api, float depthValue, bool depthMask, int stencilValue, int stencilMask) + private void ClearDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask) { if (depthMask && stencilMask != 0) { - api.ClearBuffer(GLEnum.DepthStencil, 0, depthValue, stencilValue); + _api.ClearBuffer(GLEnum.DepthStencil, 0, depthValue, stencilValue); } else if (depthMask) { - api.ClearBuffer(BufferKind.Depth, 0, ref depthValue); + _api.ClearBuffer(BufferKind.Depth, 0, ref depthValue); } else if (stencilMask != 0) { - api.ClearBuffer(BufferKind.Stencil, 0, ref stencilValue); + _api.ClearBuffer(BufferKind.Stencil, 0, ref stencilValue); } } @@ -741,9 +741,9 @@ namespace Ryujinx.Graphics.OpenGL RestoreViewport0(); - Enable(EnableCap.CullFace, _cullEnable); - Enable(EnableCap.StencilTest, _stencilTestEnable); - Enable(EnableCap.DepthTest, _depthTestEnable); + Enable(_api, EnableCap.CullFace, _cullEnable); + Enable(_api, EnableCap.StencilTest, _stencilTestEnable); + Enable(_api, EnableCap.DepthTest, _depthTestEnable); if (_depthMask) { @@ -802,17 +802,17 @@ namespace Ryujinx.Graphics.OpenGL if (!blend.Enable) { - _api.Disable(EnableCap.Blend, index); + _api.Disable(EnableCap.Blend, (uint)index); return; } _api.BlendEquationSeparate( - index, + (uint)index, blend.ColorOp.Convert(), blend.AlphaOp.Convert()); _api.BlendFuncSeparate( - index, + (uint)index, (BlendingFactor)blend.ColorSrcFactor.Convert(), (BlendingFactor)blend.ColorDstFactor.Convert(), (BlendingFactor)blend.AlphaSrcFactor.Convert(), @@ -837,7 +837,7 @@ namespace Ryujinx.Graphics.OpenGL blend.BlendConstant.Alpha); } - _api.Enable(EnableCap.Blend, index); + _api.Enable(EnableCap.Blend, (uint)index); } public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp) @@ -953,17 +953,17 @@ namespace Ryujinx.Graphics.OpenGL if (texture == null) { - _api.BindImageTexture(binding, 0, 0, true, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8); + _api.BindImageTexture((uint)binding, 0, 0, true, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8); return; } TextureBase texBase = (TextureBase)texture; - SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); + InternalFormat format = (InternalFormat)FormatTable.GetImageFormat(imageFormat); if (format != 0) { - _api.BindImageTexture(binding, texBase.Handle, 0, true, 0, BufferAccessARB.ReadWrite, format); + _api.BindImageTexture((uint)binding, texBase.Handle, 0, true, 0, BufferAccessARB.ReadWrite, format); } } @@ -1078,9 +1078,9 @@ namespace Ryujinx.Graphics.OpenGL _api.Disable(EnableCap.ProgramPointSize); } - _api.PointParameter(origin == Origin.LowerLeft + _api.PointParameter(GLEnum.PointSpriteCoordOrigin, (int)(origin == Origin.LowerLeft ? GLEnum.LowerLeft - : GLEnum.UpperLeft); + : GLEnum.UpperLeft)); // Games seem to set point size to 0 which generates a GL_INVALID_VALUE // From the spec, GL_INVALID_VALUE is generated if size is less than or equal to 0. @@ -1108,7 +1108,7 @@ namespace Ryujinx.Graphics.OpenGL return; } - _api.PrimitiveRestartIndex(index); + _api.PrimitiveRestartIndex((uint)index); _api.Enable(EnableCap.PrimitiveRestart); } @@ -1226,7 +1226,7 @@ namespace Ryujinx.Graphics.OpenGL if ((_scissorEnables & mask) == 0) { _scissorEnables |= mask; - _api.Enable(EnableCap.ScissorTest, index); + _api.Enable(EnableCap.ScissorTest, (uint)index); } } else @@ -1234,12 +1234,12 @@ namespace Ryujinx.Graphics.OpenGL if ((_scissorEnables & mask) != 0) { _scissorEnables &= ~mask; - _api.Disable(EnableCap.ScissorTest, index); + _api.Disable(EnableCap.ScissorTest, (uint)index); } } } - _api.ScissorArray(0, count, ref v[0]); + _api.ScissorArray(0, (uint)count, ref v[0]); } public void SetStencilTest(StencilTestDescriptor stencilTest) @@ -1262,9 +1262,9 @@ namespace Ryujinx.Graphics.OpenGL TriangleFace.Front, (StencilFunction)stencilTest.FrontFunc.Convert(), stencilTest.FrontFuncRef, - stencilTest.FrontFuncMask); + (uint)stencilTest.FrontFuncMask); - _api.StencilMaskSeparate(TriangleFace.Front, stencilTest.FrontMask); + _api.StencilMaskSeparate(TriangleFace.Front, (uint)stencilTest.FrontMask); _api.StencilOpSeparate( TriangleFace.Back, @@ -1276,9 +1276,9 @@ namespace Ryujinx.Graphics.OpenGL TriangleFace.Back, (StencilFunction)stencilTest.BackFunc.Convert(), stencilTest.BackFuncRef, - stencilTest.BackFuncMask); + (uint)stencilTest.BackFuncMask); - _api.StencilMaskSeparate(TriangleFace.Back, stencilTest.BackMask); + _api.StencilMaskSeparate(TriangleFace.Back, (uint)stencilTest.BackMask); _api.Enable(EnableCap.StencilTest); @@ -1339,18 +1339,18 @@ namespace Ryujinx.Graphics.OpenGL if (buffer.Handle == BufferHandle.Null) { - _api.BindBufferBase(BufferTargetARB.TransformFeedbackBuffer, i, 0); + _api.BindBufferBase(BufferTargetARB.TransformFeedbackBuffer, (uint)i, 0); continue; } if (_tfbs[i] == BufferHandle.Null) { - _tfbs[i] = Buffer.Create(); + _tfbs[i] = Buffer.Create(_api); } - Buffer.Resize(_tfbs[i], buffer.Size); - Buffer.Copy(buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size); - _api.BindBufferBase(BufferTargetARB.TransformFeedbackBuffer, i, _tfbs[i].ToUInt32()); + Buffer.Resize(_api, _tfbs[i], buffer.Size); + Buffer.Copy(_api, buffer.Handle, _tfbs[i], buffer.Offset, 0, buffer.Size); + _api.BindBufferBase(BufferTargetARB.TransformFeedbackBuffer, (uint)i, _tfbs[i].ToUInt32()); } if (_tfEnabled) @@ -1428,8 +1428,8 @@ namespace Ryujinx.Graphics.OpenGL SetOrigin(flipY ? ClipControlOrigin.UpperLeft : ClipControlOrigin.LowerLeft); - _api.ViewportArray(0, viewports.Length, viewportArray); - _api.DepthRangeArray(0, viewports.Length, depthRangeArray); + _api.ViewportArray(0, (uint)viewports.Length, viewportArray); + _api.DepthRangeArray(0, (uint)viewports.Length, depthRangeArray); } public void TextureBarrier() @@ -1453,11 +1453,11 @@ namespace Ryujinx.Graphics.OpenGL if (buffer.Handle == BufferHandle.Null) { - _api.BindBufferRange(target, assignment.Binding, 0, IntPtr.Zero, 0); + _api.BindBufferRange(target, (uint)assignment.Binding, 0, IntPtr.Zero, 0); continue; } - _api.BindBufferRange(target, assignment.Binding, buffer.Handle.ToUInt32(), (IntPtr)buffer.Offset, buffer.Size); + _api.BindBufferRange(target, (uint)assignment.Binding, buffer.Handle.ToUInt32(), buffer.Offset, (UIntPtr)buffer.Size); } } @@ -1490,7 +1490,7 @@ namespace Ryujinx.Graphics.OpenGL { if (_vertexArray == null) { - _vertexArray = new VertexArray(); + _vertexArray = new VertexArray(_api); _vertexArray.Bind(); } @@ -1551,7 +1551,7 @@ namespace Ryujinx.Graphics.OpenGL { if (_tfbTargets[i].Handle != BufferHandle.Null) { - Buffer.Copy(_tfbs[i], _tfbTargets[i].Handle, 0, _tfbTargets[i].Offset, _tfbTargets[i].Size); + Buffer.Copy(_api, _tfbs[i], _tfbTargets[i].Handle, 0, _tfbTargets[i].Offset, _tfbTargets[i].Size); } } } @@ -1629,16 +1629,16 @@ namespace Ryujinx.Graphics.OpenGL if (texBase != null) { - SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); + InternalFormat format = (InternalFormat)FormatTable.GetImageFormat(imageFormat); if (format != 0) { - _api.BindImageTexture(i, texBase.Handle, 0, true, 0, BufferAccessARB.ReadWrite, format); + _api.BindImageTexture((uint)i, texBase.Handle, 0, true, 0, BufferAccessARB.ReadWrite, format); continue; } } - _api.BindImageTexture(i, 0, 0, true, 0, BufferAccessARB.ReadWrite, SizedInternalFormat.Rgba8); + _api.BindImageTexture((uint)i, 0, 0, true, 0, BufferAccessARB.ReadWrite, InternalFormat.Rgba8); } } diff --git a/src/Ryujinx.Graphics.OpenGL/Program.cs b/src/Ryujinx.Graphics.OpenGL/Program.cs index 602032baf..7938ac906 100644 --- a/src/Ryujinx.Graphics.OpenGL/Program.cs +++ b/src/Ryujinx.Graphics.OpenGL/Program.cs @@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.OpenGL byte[] data = new byte[size + 4]; - _api.GetProgramBinary(Handle, size, out _, out ShaderBinaryFormat binFormat, data); + _api.GetProgramBinary(Handle, (uint)size, out _, out GLEnum binFormat, data); BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan(size, 4), (int)binFormat); diff --git a/src/Ryujinx.Graphics.OpenGL/VertexArray.cs b/src/Ryujinx.Graphics.OpenGL/VertexArray.cs index c3aa2184f..155f69b15 100644 --- a/src/Ryujinx.Graphics.OpenGL/VertexArray.cs +++ b/src/Ryujinx.Graphics.OpenGL/VertexArray.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.OpenGL { class VertexArray : IDisposable { - public int Handle { get; private set; } + public uint Handle { get; private set; } private readonly VertexAttribDescriptor[] _vertexAttribs; private readonly VertexBufferDescriptor[] _vertexBuffers; @@ -23,20 +23,22 @@ namespace Ryujinx.Graphics.OpenGL private readonly BufferHandle _tempIndexBuffer; private BufferHandle _tempVertexBuffer; private int _tempVertexBufferSize; + private readonly GL _api; - public VertexArray() + public VertexArray(GL api) { - Handle = GL.GenVertexArray(); + _api = api; + Handle = _api.GenVertexArray(); _vertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttribs]; _vertexBuffers = new VertexBufferDescriptor[Constants.MaxVertexBuffers]; - _tempIndexBuffer = Buffer.Create(); + _tempIndexBuffer = Buffer.Create(_api); } public void Bind() { - GL.BindVertexArray(Handle); + _api.BindVertexArray(Handle); } public void SetVertexBuffers(ReadOnlySpan vertexBuffers) @@ -56,15 +58,15 @@ namespace Ryujinx.Graphics.OpenGL minVertexCount = vertexCount; } - GL.BindVertexBuffer(bindingIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride); - GL.VertexBindingDivisor(bindingIndex, vb.Divisor); + _api.BindVertexBuffer((uint)bindingIndex, vb.Buffer.Handle.ToUInt32(), vb.Buffer.Offset, (uint)vb.Stride); + _api.VertexBindingDivisor((uint)bindingIndex, (uint)vb.Divisor); _vertexBuffersInUse |= 1u << bindingIndex; } else { if ((_vertexBuffersInUse & (1u << bindingIndex)) != 0) { - GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0); + _api.BindVertexBuffer((uint)bindingIndex, 0, IntPtr.Zero, 0); _vertexBuffersInUse &= ~(1u << bindingIndex); } } @@ -111,16 +113,16 @@ namespace Ryujinx.Graphics.OpenGL { VertexAttribType type = (VertexAttribType)fmtInfo.PixelType; - GL.VertexAttribFormat(index, size, type, fmtInfo.Normalized, offset); + _api.VertexAttribFormat((uint)index, size, type, fmtInfo.Normalized, (uint)offset); } else { - VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType; + VertexAttribIType type = (VertexAttribIType)fmtInfo.PixelType; - GL.VertexAttribIFormat(index, size, type, offset); + _api.VertexAttribIFormat((uint)index, size, type, (uint)offset); } - GL.VertexAttribBinding(index, attrib.BufferIndex); + _api.VertexAttribBinding((uint)index, (uint)attrib.BufferIndex); _vertexAttribs[index] = attrib; } @@ -134,19 +136,19 @@ namespace Ryujinx.Graphics.OpenGL public void SetIndexBuffer(BufferRange range) { _indexBuffer = range; - GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, range.Handle.ToInt32()); + _api.BindBuffer(BufferTargetARB.ElementArrayBuffer, range.Handle.ToUInt32()); } public void SetRangeOfIndexBuffer() { - Buffer.Resize(_tempIndexBuffer, _indexBuffer.Size); - Buffer.Copy(_indexBuffer.Handle, _tempIndexBuffer, _indexBuffer.Offset, 0, _indexBuffer.Size); - GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, _tempIndexBuffer.ToInt32()); + Buffer.Resize(_api, _tempIndexBuffer, _indexBuffer.Size); + Buffer.Copy(_api, _indexBuffer.Handle, _tempIndexBuffer, _indexBuffer.Offset, 0, _indexBuffer.Size); + _api.BindBuffer(BufferTargetARB.ElementArrayBuffer, _tempIndexBuffer.ToUInt32()); } public void RestoreIndexBuffer() { - GL.BindBuffer(BufferTargetARB.ElementArrayBuffer, _indexBuffer.Handle.ToInt32()); + _api.BindBuffer(BufferTargetARB.ElementArrayBuffer, _indexBuffer.Handle.ToUInt32()); } public void PreDraw(int vertexCount) @@ -185,10 +187,10 @@ namespace Ryujinx.Graphics.OpenGL { BufferHandle tempVertexBuffer = EnsureTempVertexBufferSize(currentTempVbOffset + requiredSize); - Buffer.Copy(vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size); - Buffer.Clear(tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, requiredSize - vb.Buffer.Size, 0); + Buffer.Copy(_api, vb.Buffer.Handle, tempVertexBuffer, vb.Buffer.Offset, currentTempVbOffset, vb.Buffer.Size); + Buffer.Clear(_api, tempVertexBuffer, currentTempVbOffset + vb.Buffer.Size, (uint)(requiredSize - vb.Buffer.Size), 0); - GL.BindVertexBuffer(vbIndex, tempVertexBuffer.ToInt32(), (IntPtr)currentTempVbOffset, vb.Stride); + _api.BindVertexBuffer((uint)vbIndex, tempVertexBuffer.ToUInt32(), (IntPtr)currentTempVbOffset, (uint)vb.Stride); currentTempVbOffset += requiredSize; _vertexBuffersLimited |= 1u << vbIndex; @@ -208,12 +210,12 @@ namespace Ryujinx.Graphics.OpenGL if (tempVertexBuffer == BufferHandle.Null) { - tempVertexBuffer = Buffer.Create(size); + tempVertexBuffer = Buffer.Create(_api, size); _tempVertexBuffer = tempVertexBuffer; return tempVertexBuffer; } - Buffer.Resize(_tempVertexBuffer, size); + Buffer.Resize(_api, _tempVertexBuffer, size); } return tempVertexBuffer; @@ -234,7 +236,7 @@ namespace Ryujinx.Graphics.OpenGL ref var vb = ref _vertexBuffers[vbIndex]; - GL.BindVertexBuffer(vbIndex, vb.Buffer.Handle.ToInt32(), (IntPtr)vb.Buffer.Offset, vb.Stride); + _api.BindVertexBuffer((uint)vbIndex, vb.Buffer.Handle.ToUInt32(), (IntPtr)vb.Buffer.Offset, (uint)vb.Stride); buffersLimited &= ~(1u << vbIndex); } @@ -250,7 +252,7 @@ namespace Ryujinx.Graphics.OpenGL if ((_vertexAttribsInUse & mask) == 0) { _vertexAttribsInUse |= mask; - GL.EnableVertexAttribArray(index); + _api.EnableVertexAttribArray((uint)index); } } @@ -262,8 +264,8 @@ namespace Ryujinx.Graphics.OpenGL if ((_vertexAttribsInUse & mask) != 0) { _vertexAttribsInUse &= ~mask; - GL.DisableVertexAttribArray(index); - GL.VertexAttrib4(index, 0f, 0f, 0f, 1f); + _api.DisableVertexAttribArray((uint)index); + _api.VertexAttrib4((uint)index, 0f, 0f, 0f, 1f); } } @@ -271,7 +273,7 @@ namespace Ryujinx.Graphics.OpenGL { if (Handle != 0) { - GL.DeleteVertexArray(Handle); + _api.DeleteVertexArray(Handle); Handle = 0; } diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs index 2347b8955..3741a9a9c 100644 --- a/src/Ryujinx.Graphics.OpenGL/Window.cs +++ b/src/Ryujinx.Graphics.OpenGL/Window.cs @@ -252,12 +252,13 @@ namespace Ryujinx.Graphics.OpenGL _initialized = true; } - public void CaptureFrame(int x, int y, uint width, uint height, bool isBgra, bool flipX, bool flipY) + public unsafe void CaptureFrame(int x, int y, uint width, uint height, bool isBgra, bool flipX, bool flipY) { long size = 4 * width * height; - byte[] bitmap = new byte[size]; - _gd.Api.ReadPixels(x, y, width, height, isBgra ? PixelFormat.Bgra : PixelFormat.Rgba, PixelType.UnsignedByte, bitmap); + _gd.Api.ReadPixels(x, y, width, height, isBgra ? PixelFormat.Bgra : PixelFormat.Rgba, PixelType.UnsignedByte, out int data); + + var bitmap = new Span((void*)data, (int)size).ToArray(); _gd.OnScreenCaptured(new ScreenCaptureImageInfo((int)width, (int)height, isBgra, bitmap, flipX, flipY)); }