From d7e9668d506ff5cb08c6d5481481362614214c7d Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Tue, 16 Jul 2024 06:18:45 +1000 Subject: [PATCH] Add and use `Span`-from-`IntPtr` helper --- src/BizHawk.Bizware.Audio/SDL2WavStream.cs | 13 +++++---- .../D3D11/D3D11Pipeline.cs | 16 +++++------ .../D3D11/IGL_D3D11.cs | 8 +++--- .../OpenGL/OpenGLPipeline.cs | 11 ++++---- .../Renderers/ImGui2DRenderer.cs | 5 ++-- .../Extensions/NumberExtensions.cs | 11 ++++++++ src/BizHawk.Common/Util.cs | 27 +++++++++++++++++-- .../Waterbox/NymaCore.Settings.cs | 11 ++++---- .../Waterbox/WaterboxHost.cs | 12 ++++----- 9 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/BizHawk.Bizware.Audio/SDL2WavStream.cs b/src/BizHawk.Bizware.Audio/SDL2WavStream.cs index 8c098e24b4..859f0bf78d 100644 --- a/src/BizHawk.Bizware.Audio/SDL2WavStream.cs +++ b/src/BizHawk.Bizware.Audio/SDL2WavStream.cs @@ -3,6 +3,7 @@ using System.IO; using System.Runtime.InteropServices; using BizHawk.Common; +using BizHawk.Common.NumberExtensions; using static SDL2.SDL; @@ -91,17 +92,19 @@ namespace BizHawk.Bizware.Audio { } - public unsafe int Read(Span buffer) + public int Read(Span buffer) { if (_wav == IntPtr.Zero) { throw new ObjectDisposedException(nameof(SDL2WavStream)); } - var count = (int)Math.Min(buffer.Length, _len - _pos); - new ReadOnlySpan((void*)((nint)_wav + _pos), count).CopyTo(buffer); - _pos += (uint)count; - return count; + uint count = Math.Min((uint) buffer.Length, _len - _pos); + var countSigned = unchecked((int) count); // since `Span.Length` is at most `int.MaxValue`, so must `count` be + // really, these fields should just be widened to whatever they're used as, which seems to be s64, and asserted to be in 0..((void*)data, count * VertexStride); - + ReadOnlySpan vertexes = Util.UnsafeSpanFromPointer(ptr: data, length: count * VertexStride); // BufferData reallocs and BufferSubData doesn't, so only use the former if we need to grow the buffer if (vertexes.Length > VertexBufferLen) { @@ -225,10 +225,9 @@ namespace BizHawk.Bizware.Graphics } } - public unsafe void SetIndexData(IntPtr data, int count) + public void SetIndexData(IntPtr data, int count) { - var indexes = new ReadOnlySpan((void*)data, count * 2); - + ReadOnlySpan indexes = Util.UnsafeSpanFromPointer(ptr: data, length: count * 2); if (indexes.Length > IndexBufferLen) { GL.BufferData(GLEnum.ElementArrayBuffer, indexes, GLEnum.DynamicDraw); diff --git a/src/BizHawk.Bizware.Graphics/Renderers/ImGui2DRenderer.cs b/src/BizHawk.Bizware.Graphics/Renderers/ImGui2DRenderer.cs index 9868ff11a7..67837a3757 100644 --- a/src/BizHawk.Bizware.Graphics/Renderers/ImGui2DRenderer.cs +++ b/src/BizHawk.Bizware.Graphics/Renderers/ImGui2DRenderer.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using ImGuiNET; +using BizHawk.Common; using BizHawk.Common.CollectionExtensions; using SDGraphics = System.Drawing.Graphics; @@ -91,10 +92,10 @@ namespace BizHawk.Bizware.Graphics _imGuiDrawList = IntPtr.Zero; } - private unsafe void ClearStringOutput() + private void ClearStringOutput() { var bmpData = _stringOutput.LockBits(new(0, 0, _stringOutput.Width, _stringOutput.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - new Span((void*)bmpData.Scan0, bmpData.Stride * bmpData.Height).Clear(); + Util.UnsafeSpanFromPointer(ptr: bmpData.Scan0, length: bmpData.Stride * bmpData.Height).Clear(); _stringOutput.UnlockBits(bmpData); } diff --git a/src/BizHawk.Common/Extensions/NumberExtensions.cs b/src/BizHawk.Common/Extensions/NumberExtensions.cs index e1aaf15f59..0f236461f2 100644 --- a/src/BizHawk.Common/Extensions/NumberExtensions.cs +++ b/src/BizHawk.Common/Extensions/NumberExtensions.cs @@ -121,6 +121,17 @@ namespace BizHawk.Common.NumberExtensions return val; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IntPtr Plus(this IntPtr p, int offset) + => p + offset; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IntPtr Plus(this IntPtr p, uint offset) + { + var half = unchecked((int) offset >> 1); + return p + half + unchecked((int) (offset - half)); + } + public static void RotateRightU8(ref byte b, int shift) { byte temp = b; diff --git a/src/BizHawk.Common/Util.cs b/src/BizHawk.Common/Util.cs index da11ec93a2..7b37bf9427 100644 --- a/src/BizHawk.Common/Util.cs +++ b/src/BizHawk.Common/Util.cs @@ -4,9 +4,7 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; -#if NETCOREAPP3_0_OR_GREATER using System.Runtime.CompilerServices; -#endif using System.Threading; namespace BizHawk.Common @@ -381,6 +379,31 @@ namespace BizHawk.Common } } + /// creates span over octets starting at + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span UnsafeSpanFromPointer(IntPtr ptr, int length) + { + unsafe + { + return new(pointer: ptr.ToPointer(), length: length); + } + } + + /// + /// creates span over * sizeof() octets + /// starting at + /// + /// uses native endianness + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Span UnsafeSpanFromPointer(IntPtr ptr, int count) + where T : unmanaged + { + unsafe + { + return new(pointer: ptr.ToPointer(), length: count * sizeof(T)); + } + } + public static void WriteByteBuffer(this BinaryWriter bw, byte[]? data) { if (data == null) diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Settings.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Settings.cs index 285733c6fa..b4a6bd828d 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Settings.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Settings.cs @@ -1,7 +1,8 @@ using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; using System.Text; + +using BizHawk.Common; using BizHawk.Emulation.Common; using NymaTypes; @@ -214,7 +215,7 @@ namespace BizHawk.Emulation.Cores.Waterbox return val; } - private unsafe void SettingsQuery(string name, IntPtr dest) + private void SettingsQuery(string name, IntPtr dest) { var val = SettingsQuery(name); var bytes = val is null ? Array.Empty() : Encoding.UTF8.GetBytes(val); @@ -222,9 +223,9 @@ namespace BizHawk.Emulation.Cores.Waterbox { throw new InvalidOperationException($"Value {val} for setting {name} was too long"); } - - new Span((void*)dest, 256).Clear(); - Marshal.Copy(bytes, 0, dest, bytes.Length); + var dstSpan = Util.UnsafeSpanFromPointer(ptr: dest, length: 256); + dstSpan.Clear(); + bytes.CopyTo(dstSpan); } private LibNymaCore.FrontendSettingQuery _settingsQueryDelegate; diff --git a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs index 7a3ed81740..4779521bf3 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs @@ -99,12 +99,12 @@ namespace BizHawk.Emulation.Cores.Waterbox _handle = GCHandle.Alloc(this, GCHandleType.Weak); } - public unsafe IntPtr Read(IntPtr data, UIntPtr size) + public IntPtr Read(IntPtr data, UIntPtr size) { + var count = checked((int) size); try { - var count = (int)size; - var n = _backingSpanStream.Read(new((void*)data, count)); + var n = _backingSpanStream.Read(Util.UnsafeSpanFromPointer(ptr: data, length: count)); return Z.SS(n); } catch @@ -113,12 +113,12 @@ namespace BizHawk.Emulation.Cores.Waterbox } } - public unsafe int Write(IntPtr data, UIntPtr size) + public int Write(IntPtr data, UIntPtr size) { + var count = checked((int) size); try { - var count = (int)size; - _backingSpanStream.Write(new((void*)data, count)); + _backingSpanStream.Write(Util.UnsafeSpanFromPointer(ptr: data, length: count)); return 0; } catch