Add and use `Span`-from-`IntPtr` helper

This commit is contained in:
YoshiRulz 2024-07-16 06:18:45 +10:00
parent f742fe55d5
commit d7e9668d50
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
9 changed files with 75 additions and 39 deletions

View File

@ -3,6 +3,7 @@ using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using static SDL2.SDL; using static SDL2.SDL;
@ -91,17 +92,19 @@ namespace BizHawk.Bizware.Audio
{ {
} }
public unsafe int Read(Span<byte> buffer) public int Read(Span<byte> buffer)
{ {
if (_wav == IntPtr.Zero) if (_wav == IntPtr.Zero)
{ {
throw new ObjectDisposedException(nameof(SDL2WavStream)); throw new ObjectDisposedException(nameof(SDL2WavStream));
} }
var count = (int)Math.Min(buffer.Length, _len - _pos); uint count = Math.Min((uint) buffer.Length, _len - _pos);
new ReadOnlySpan<byte>((void*)((nint)_wav + _pos), count).CopyTo(buffer); var countSigned = unchecked((int) count); // since `Span.Length` is at most `int.MaxValue`, so must `count` be
_pos += (uint)count; // really, these fields should just be widened to whatever they're used as, which seems to be s64, and asserted to be in 0..<int.MaxValue
return count; Util.UnsafeSpanFromPointer(ptr: _wav.Plus(_pos), length: countSigned).CopyTo(buffer);
_pos += count;
return countSigned;
} }
public override int Read(byte[] buffer, int offset, int count) public override int Read(byte[] buffer, int offset, int count)

View File

@ -2,6 +2,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions; using BizHawk.Common.CollectionExtensions;
using BizHawk.Common.StringExtensions; using BizHawk.Common.StringExtensions;
@ -303,11 +305,8 @@ namespace BizHawk.Bizware.Graphics
var mappedVb = Context.Map(VertexBuffer, MapMode.WriteDiscard); var mappedVb = Context.Map(VertexBuffer, MapMode.WriteDiscard);
try try
{ {
unsafe Util.UnsafeSpanFromPointer(ptr: data, length: count * VertexStride)
{ .CopyTo(Util.UnsafeSpanFromPointer(ptr: mappedVb.DataPointer, length: VertexBufferCount * VertexStride));
Buffer.MemoryCopy((void*)data, (void*)mappedVb.DataPointer,
VertexBufferCount * VertexStride, count * VertexStride);
}
} }
finally finally
{ {
@ -331,11 +330,8 @@ namespace BizHawk.Bizware.Graphics
var mappedIb = Context.Map(IndexBuffer, MapMode.WriteDiscard); var mappedIb = Context.Map(IndexBuffer, MapMode.WriteDiscard);
try try
{ {
unsafe Util.UnsafeSpanFromPointer(ptr: data, length: count * 2)
{ .CopyTo(Util.UnsafeSpanFromPointer(ptr: mappedIb.DataPointer, length: IndexBufferCount * 2));
Buffer.MemoryCopy((void*)data, (void*)mappedIb.DataPointer,
IndexBufferCount * 2, count * 2);
}
} }
finally finally
{ {

View File

@ -269,7 +269,7 @@ namespace BizHawk.Bizware.Graphics
Context.OMSetRenderTargets(_controlSwapChain.RTV); Context.OMSetRenderTargets(_controlSwapChain.RTV);
} }
private unsafe void UpdateConstantBuffers() private void UpdateConstantBuffers()
{ {
for (var i = 0; i < ID3D11DeviceContext.CommonShaderConstantBufferSlotCount; i++) for (var i = 0; i < ID3D11DeviceContext.CommonShaderConstantBufferSlotCount; i++)
{ {
@ -282,7 +282,8 @@ namespace BizHawk.Bizware.Graphics
if (pb.VSBufferDirty) if (pb.VSBufferDirty)
{ {
var vsCb = Context.Map(CurPipeline.VSConstantBuffers[i], MapMode.WriteDiscard); var vsCb = Context.Map(CurPipeline.VSConstantBuffers[i], MapMode.WriteDiscard);
Buffer.MemoryCopy((void*)pb.VSPendingBuffer, (void*)vsCb.DataPointer, pb.VSBufferSize, pb.VSBufferSize); Util.UnsafeSpanFromPointer(ptr: pb.VSPendingBuffer, length: pb.VSBufferSize)
.CopyTo(Util.UnsafeSpanFromPointer(ptr: vsCb.DataPointer, length: pb.VSBufferSize));
Context.Unmap(CurPipeline.VSConstantBuffers[i]); Context.Unmap(CurPipeline.VSConstantBuffers[i]);
pb.VSBufferDirty = false; pb.VSBufferDirty = false;
} }
@ -290,7 +291,8 @@ namespace BizHawk.Bizware.Graphics
if (pb.PSBufferDirty) if (pb.PSBufferDirty)
{ {
var psCb = Context.Map(CurPipeline.PSConstantBuffers[i], MapMode.WriteDiscard); var psCb = Context.Map(CurPipeline.PSConstantBuffers[i], MapMode.WriteDiscard);
Buffer.MemoryCopy((void*)pb.PSPendingBuffer, (void*)psCb.DataPointer, pb.PSBufferSize, pb.PSBufferSize); Util.UnsafeSpanFromPointer(ptr: pb.PSPendingBuffer, length: pb.PSBufferSize)
.CopyTo(Util.UnsafeSpanFromPointer(ptr: psCb.DataPointer, length: pb.PSBufferSize));
Context.Unmap(CurPipeline.PSConstantBuffers[i]); Context.Unmap(CurPipeline.PSConstantBuffers[i]);
pb.PSBufferDirty = false; pb.PSBufferDirty = false;
} }

View File

@ -4,6 +4,7 @@ using System.Numerics;
using Silk.NET.OpenGL; using Silk.NET.OpenGL;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions; using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Bizware.Graphics namespace BizHawk.Bizware.Graphics
@ -209,10 +210,9 @@ namespace BizHawk.Bizware.Graphics
GL.DeleteBuffer(VBO); GL.DeleteBuffer(VBO);
} }
public unsafe void SetVertexData(IntPtr data, int count) public void SetVertexData(IntPtr data, int count)
{ {
var vertexes = new ReadOnlySpan<byte>((void*)data, count * VertexStride); ReadOnlySpan<byte> 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 // BufferData reallocs and BufferSubData doesn't, so only use the former if we need to grow the buffer
if (vertexes.Length > VertexBufferLen) 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<byte>((void*)data, count * 2); ReadOnlySpan<byte> indexes = Util.UnsafeSpanFromPointer(ptr: data, length: count * 2);
if (indexes.Length > IndexBufferLen) if (indexes.Length > IndexBufferLen)
{ {
GL.BufferData(GLEnum.ElementArrayBuffer, indexes, GLEnum.DynamicDraw); GL.BufferData(GLEnum.ElementArrayBuffer, indexes, GLEnum.DynamicDraw);

View File

@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
using ImGuiNET; using ImGuiNET;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions; using BizHawk.Common.CollectionExtensions;
using SDGraphics = System.Drawing.Graphics; using SDGraphics = System.Drawing.Graphics;
@ -91,10 +92,10 @@ namespace BizHawk.Bizware.Graphics
_imGuiDrawList = IntPtr.Zero; _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); var bmpData = _stringOutput.LockBits(new(0, 0, _stringOutput.Width, _stringOutput.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
new Span<byte>((void*)bmpData.Scan0, bmpData.Stride * bmpData.Height).Clear(); Util.UnsafeSpanFromPointer(ptr: bmpData.Scan0, length: bmpData.Stride * bmpData.Height).Clear();
_stringOutput.UnlockBits(bmpData); _stringOutput.UnlockBits(bmpData);
} }

View File

@ -121,6 +121,17 @@ namespace BizHawk.Common.NumberExtensions
return val; 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) public static void RotateRightU8(ref byte b, int shift)
{ {
byte temp = b; byte temp = b;

View File

@ -4,9 +4,7 @@ using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
#if NETCOREAPP3_0_OR_GREATER
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
#endif
using System.Threading; using System.Threading;
namespace BizHawk.Common namespace BizHawk.Common
@ -381,6 +379,31 @@ namespace BizHawk.Common
} }
} }
/// <summary>creates span over <paramref name="length"/> octets starting at <paramref name="ptr"/></summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<byte> UnsafeSpanFromPointer(IntPtr ptr, int length)
{
unsafe
{
return new(pointer: ptr.ToPointer(), length: length);
}
}
/// <summary>
/// creates span over <paramref name="count"/><c> * sizeof(</c><typeparamref name="T"/><c>)</c> octets
/// starting at <paramref name="ptr"/>
/// </summary>
/// <remarks>uses native endianness</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<T> UnsafeSpanFromPointer<T>(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) public static void WriteByteBuffer(this BinaryWriter bw, byte[]? data)
{ {
if (data == null) if (data == null)

View File

@ -1,7 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using BizHawk.Common;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using NymaTypes; using NymaTypes;
@ -214,7 +215,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
return val; return val;
} }
private unsafe void SettingsQuery(string name, IntPtr dest) private void SettingsQuery(string name, IntPtr dest)
{ {
var val = SettingsQuery(name); var val = SettingsQuery(name);
var bytes = val is null ? Array.Empty<byte>() : Encoding.UTF8.GetBytes(val); var bytes = val is null ? Array.Empty<byte>() : Encoding.UTF8.GetBytes(val);
@ -222,9 +223,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
{ {
throw new InvalidOperationException($"Value {val} for setting {name} was too long"); throw new InvalidOperationException($"Value {val} for setting {name} was too long");
} }
var dstSpan = Util.UnsafeSpanFromPointer(ptr: dest, length: 256);
new Span<byte>((void*)dest, 256).Clear(); dstSpan.Clear();
Marshal.Copy(bytes, 0, dest, bytes.Length); bytes.CopyTo(dstSpan);
} }
private LibNymaCore.FrontendSettingQuery _settingsQueryDelegate; private LibNymaCore.FrontendSettingQuery _settingsQueryDelegate;

View File

@ -99,12 +99,12 @@ namespace BizHawk.Emulation.Cores.Waterbox
_handle = GCHandle.Alloc(this, GCHandleType.Weak); _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 try
{ {
var count = (int)size; var n = _backingSpanStream.Read(Util.UnsafeSpanFromPointer(ptr: data, length: count));
var n = _backingSpanStream.Read(new((void*)data, count));
return Z.SS(n); return Z.SS(n);
} }
catch 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 try
{ {
var count = (int)size; _backingSpanStream.Write(Util.UnsafeSpanFromPointer(ptr: data, length: count));
_backingSpanStream.Write(new((void*)data, count));
return 0; return 0;
} }
catch catch