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 BizHawk.Common;
using BizHawk.Common.NumberExtensions;
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)
{
throw new ObjectDisposedException(nameof(SDL2WavStream));
}
var count = (int)Math.Min(buffer.Length, _len - _pos);
new ReadOnlySpan<byte>((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..<int.MaxValue
Util.UnsafeSpanFromPointer(ptr: _wav.Plus(_pos), length: countSigned).CopyTo(buffer);
_pos += count;
return countSigned;
}
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.Numerics;
using System.Runtime.InteropServices;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Common.StringExtensions;
@ -303,11 +305,8 @@ namespace BizHawk.Bizware.Graphics
var mappedVb = Context.Map(VertexBuffer, MapMode.WriteDiscard);
try
{
unsafe
{
Buffer.MemoryCopy((void*)data, (void*)mappedVb.DataPointer,
VertexBufferCount * VertexStride, count * VertexStride);
}
Util.UnsafeSpanFromPointer(ptr: data, length: count * VertexStride)
.CopyTo(Util.UnsafeSpanFromPointer(ptr: mappedVb.DataPointer, length: VertexBufferCount * VertexStride));
}
finally
{
@ -331,11 +330,8 @@ namespace BizHawk.Bizware.Graphics
var mappedIb = Context.Map(IndexBuffer, MapMode.WriteDiscard);
try
{
unsafe
{
Buffer.MemoryCopy((void*)data, (void*)mappedIb.DataPointer,
IndexBufferCount * 2, count * 2);
}
Util.UnsafeSpanFromPointer(ptr: data, length: count * 2)
.CopyTo(Util.UnsafeSpanFromPointer(ptr: mappedIb.DataPointer, length: IndexBufferCount * 2));
}
finally
{

View File

@ -269,7 +269,7 @@ namespace BizHawk.Bizware.Graphics
Context.OMSetRenderTargets(_controlSwapChain.RTV);
}
private unsafe void UpdateConstantBuffers()
private void UpdateConstantBuffers()
{
for (var i = 0; i < ID3D11DeviceContext.CommonShaderConstantBufferSlotCount; i++)
{
@ -282,7 +282,8 @@ namespace BizHawk.Bizware.Graphics
if (pb.VSBufferDirty)
{
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]);
pb.VSBufferDirty = false;
}
@ -290,7 +291,8 @@ namespace BizHawk.Bizware.Graphics
if (pb.PSBufferDirty)
{
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]);
pb.PSBufferDirty = false;
}

View File

@ -4,6 +4,7 @@ using System.Numerics;
using Silk.NET.OpenGL;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
namespace BizHawk.Bizware.Graphics
@ -209,10 +210,9 @@ namespace BizHawk.Bizware.Graphics
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
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)
{
GL.BufferData(GLEnum.ElementArrayBuffer, indexes, GLEnum.DynamicDraw);

View File

@ -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<byte>((void*)bmpData.Scan0, bmpData.Stride * bmpData.Height).Clear();
Util.UnsafeSpanFromPointer(ptr: bmpData.Scan0, length: bmpData.Stride * bmpData.Height).Clear();
_stringOutput.UnlockBits(bmpData);
}

View File

@ -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;

View File

@ -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
}
}
/// <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)
{
if (data == null)

View File

@ -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<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");
}
new Span<byte>((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;

View File

@ -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