diff --git a/src/Vortice.Win32/Graphics/Dxgi.Manual.cs b/src/Vortice.Win32/Graphics/Dxgi.Manual.cs
index 6fd69ed..c03ad1b 100644
--- a/src/Vortice.Win32/Graphics/Dxgi.Manual.cs
+++ b/src/Vortice.Win32/Graphics/Dxgi.Manual.cs
@@ -2,9 +2,66 @@
// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
using static Win32.Graphics.Dxgi.Apis;
+using static Win32.StringUtilities;
namespace Win32.Graphics.Dxgi;
+public unsafe partial struct AdapterDescription
+{
+ ///
+ public readonly string DescriptionStr
+ {
+ get
+ {
+ fixed (ushort* ptr = Description)
+ {
+ return GetString(ptr, 128) ?? string.Empty;
+ }
+ }
+ }
+}
+
+public unsafe partial struct AdapterDescription1
+{
+ ///
+ public readonly string DescriptionStr
+ {
+ get
+ {
+ fixed (ushort* ptr = Description)
+ {
+ return GetString(ptr, 128) ?? string.Empty;
+ }
+ }
+ }
+}
+
+public unsafe partial struct AdapterDescription2
+{
+ public readonly ReadOnlySpan DescriptionSpan
+ {
+ get
+ {
+ fixed (ushort* ptr = Description)
+ {
+ return GetUtf16Span(ptr, 128);
+ }
+ }
+ }
+
+ ///
+ public readonly string DescriptionStr
+ {
+ get
+ {
+ fixed (ushort* ptr = Description)
+ {
+ return GetString(ptr, 128) ?? string.Empty;
+ }
+ }
+ }
+}
+
public unsafe partial struct IDXGIFactory5
{
public TFeature CheckFeatureSupport(Feature feature)
diff --git a/src/Vortice.Win32/NetStandard.cs b/src/Vortice.Win32/NetStandard.cs
index e3a0272..e005052 100644
--- a/src/Vortice.Win32/NetStandard.cs
+++ b/src/Vortice.Win32/NetStandard.cs
@@ -23,6 +23,17 @@ internal static class MemoryMarshal
return ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(span);
}
+ ///
+ /// Returns a reference to the 0th element of . If the array is empty, returns a reference
+ /// to where the 0th element would have been stored. Such a reference may be used for pinning but must never be dereferenced.
+ ///
+ /// is .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetArrayDataReference(T[] array)
+ {
+ return ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(array.AsSpan());
+ }
+
///
/// Creates a new from a given reference.
///
@@ -34,6 +45,18 @@ internal static class MemoryMarshal
{
return new(Unsafe.AsPointer(ref value), length);
}
+
+ ///
+ /// Creates a new from a given reference.
+ ///
+ /// The type of reference to wrap.
+ /// The target reference.
+ /// The length of the to create.
+ /// A new wrapping .
+ public static unsafe ReadOnlySpan CreateReadOnlySpan(ref T value, int length)
+ {
+ return new(Unsafe.AsPointer(ref value), length);
+ }
}
#endif
diff --git a/src/Vortice.Win32/StringUtilities.cs b/src/Vortice.Win32/StringUtilities.cs
new file mode 100644
index 0000000..9a1ac1a
--- /dev/null
+++ b/src/Vortice.Win32/StringUtilities.cs
@@ -0,0 +1,176 @@
+// Copyright © Amer Koleci and Contributors.
+// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
+// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Text;
+using static Win32.UnsafeUtilities;
+
+namespace Win32;
+
+///
+/// Provides a set of methods to supplement for .
+///
+public static unsafe class StringUtilities
+{
+ public static string? GetString(sbyte* pointer, int maxLength = -1)
+ {
+ return GetUtf8Span(pointer, maxLength).GetString();
+ }
+
+ public static string? GetString(ushort* pointer, int maxLength = -1)
+ {
+ return GetUtf16Span(pointer, maxLength).GetString();
+ }
+
+ /// Gets a null-terminated sequence of UTF8 characters for a string.
+ /// The string for which to get the null-terminated UTF8 character sequence.
+ /// A null-terminated UTF8 character sequence created from .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan GetUtf8Span(this string? source)
+ {
+ ReadOnlySpan result;
+
+ if (source is not null)
+ {
+ int maxLength = Encoding.UTF8.GetMaxByteCount(source.Length);
+#if NET6_0_OR_GREATER
+ var bytes = new byte[maxLength + 1];
+ var length = Encoding.UTF8.GetBytes(source, bytes);
+ result = bytes.AsSpan(0, length);
+#else
+ byte* bytes = stackalloc byte[maxLength + 1];
+ fixed (char* namePtr = source)
+ {
+ Encoding.UTF8.GetBytes(namePtr, source.Length, bytes, maxLength);
+ }
+ bytes[maxLength] = 0;
+ result = new(bytes, source.Length);
+#endif
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result.As();
+ }
+
+ /// Gets a span for a null-terminated UTF8 character sequence.
+ /// The pointer to a null-terminated UTF8 character sequence.
+ /// The maxmimum length of or -1 if the maximum length is unknown.
+ /// A span that starts at and extends to or the first null character, whichever comes first.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan GetUtf8Span(sbyte* source, int maxLength = -1)
+ => (source != null) ? GetUtf8Span(in source[0], maxLength) : null;
+
+ /// Gets a span for a null-terminated UTF8 character sequence.
+ /// The reference to a null-terminated UTF8 character sequence.
+ /// The maxmimum length of or -1 if the maximum length is unknown.
+ /// A span that starts at and extends to or the first null character, whichever comes first.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan GetUtf8Span(in sbyte source, int maxLength = -1)
+ {
+ ReadOnlySpan result;
+
+ if (!IsNullRef(in source))
+ {
+ if (maxLength < 0)
+ {
+ maxLength = int.MaxValue;
+ }
+
+ result = CreateReadOnlySpan(in source, maxLength);
+ var length = result.IndexOf((sbyte)'\0');
+
+ if (length != -1)
+ {
+ result = result.Slice(0, length);
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
+ /// Gets a null-terminated sequence of UTF16 characters for a string.
+ /// The string for which to get the null-terminated UTF16 character sequence.
+ /// A null-terminated UTF16 character sequence created from .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan GetUtf16Span(this string? source) => source.AsSpan().As();
+
+ /// Marshals a null-terminated UTF16 string to a .
+ /// The pointer to a null-terminated UTF16 string.
+ /// The maxmimum length of or -1 if the maximum length is unknown.
+ /// A that starts at and extends to or the first null character, whichever comes first.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan GetUtf16Span(ushort* source, int maxLength = -1)
+ => (source != null) ? GetUtf16Span(in source[0], maxLength) : null;
+
+ /// Marshals a null-terminated UTF16 string to a .
+ /// The reference to a null-terminated UTF16 string.
+ /// The maxmimum length of or -1 if the maximum length is unknown.
+ /// A that starts at and extends to or the first null character, whichever comes first.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan GetUtf16Span(in ushort source, int maxLength = -1)
+ {
+ ReadOnlySpan result;
+
+ if (!IsNullRef(in source))
+ {
+ if (maxLength < 0)
+ {
+ maxLength = int.MaxValue;
+ }
+
+ result = CreateReadOnlySpan(in source, maxLength);
+ var length = result.IndexOf('\0');
+
+ if (length != -1)
+ {
+ result = result.Slice(0, length);
+ }
+ }
+ else
+ {
+ result = null;
+ }
+
+ return result;
+ }
+
+ /// Gets a string for a given span.
+ /// The span for which to create the string.
+ /// A string created from .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string? GetString(this ReadOnlySpan span)
+ {
+ if (span.GetPointer() == null)
+ return null;
+
+#if NET6_0_OR_GREATER
+ return new string(span.As());
+#else
+ return new string(span.As().GetPointer(), 0, span.Length);
+#endif
+ }
+
+ /// Gets a string for a given span.
+ /// The span for which to create the string.
+ /// A string created from .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string? GetString(this ReadOnlySpan span)
+ {
+ if (span.GetPointer() == null)
+ return null;
+
+#if NET6_0_OR_GREATER
+ return Encoding.UTF8.GetString(span.As());
+#else
+ return Encoding.UTF8.GetString(span.As().GetPointer(), span.Length);
+#endif
+ }
+}
diff --git a/src/Vortice.Win32/UnsafeUtilities.cs b/src/Vortice.Win32/UnsafeUtilities.cs
new file mode 100644
index 0000000..85f40c3
--- /dev/null
+++ b/src/Vortice.Win32/UnsafeUtilities.cs
@@ -0,0 +1,171 @@
+// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
+// Copyright © Amer Koleci and Contributors.
+// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information.
+
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
+#if !NET6_0_OR_GREATER
+using MemoryMarshal = Win32.MemoryMarshal;
+#endif
+
+namespace Win32;
+
+/// Provides a set of methods to supplement or replace and .
+public static unsafe class UnsafeUtilities
+{
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#if NET6_0_OR_GREATER
+ [return: NotNullIfNotNull("o")]
+#endif
+ public static T? As(this object? o)
+ where T : class?
+ {
+ //Assert(o is null or T);
+ return Unsafe.As(o);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref TTo As(ref TFrom source)
+ => ref Unsafe.As(ref source);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Span As(this Span span)
+ where TFrom : unmanaged
+ where TTo : unmanaged
+ {
+ //Assert(AssertionsEnabled && (SizeOf() == SizeOf()));
+ return CreateSpan(ref As(ref span.GetReference()), span.Length);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ReadOnlySpan As(this ReadOnlySpan span)
+ where TFrom : unmanaged
+ where TTo : unmanaged
+ {
+ //Assert(AssertionsEnabled && (SizeOf() == SizeOf()));
+ return CreateReadOnlySpan(in AsReadOnly(in span.GetReference()), span.Length);
+ }
+
+ /// Reinterprets the given native integer as a reference.
+ /// The type of the reference.
+ /// The native integer to reinterpret.
+ /// A reference to a value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef(nint source) => ref Unsafe.AsRef((void*)source);
+
+ /// Reinterprets the given native unsigned integer as a reference.
+ /// The type of the reference.
+ /// The native unsigned integer to reinterpret.
+ /// A reference to a value of type .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef(nuint source) => ref Unsafe.AsRef((void*)source);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef(in T source) => ref Unsafe.AsRef(in source);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref TTo AsRef(in TFrom source)
+ {
+ ref var mutable = ref AsRef(in source);
+ return ref As(ref mutable);
+ }
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T* AsPointer(ref T source)
+ where T : unmanaged => (T*)Unsafe.AsPointer(ref source);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref readonly TTo AsReadOnly(in TFrom source)
+ => ref Unsafe.As(ref AsRef(in source));
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T* AsReadOnlyPointer(in T source)
+ where T : unmanaged => AsPointer(ref AsRef(in source));
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T AsRef(void* source) => ref Unsafe.AsRef(source);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetReference(this T[] array) => ref MemoryMarshal.GetArrayDataReference(array);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetReference(this T[] array, int index) => ref Unsafe.Add(ref array.GetReference(), index);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetReference(this T[] array, nuint index) => ref Unsafe.Add(ref array.GetReference(), index);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetReference(this Span span) => ref MemoryMarshal.GetReference(span);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetReference(this Span span, int index) => ref Unsafe.Add(ref MemoryMarshal.GetReference(span), index);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetReference(this Span span, nuint index) => ref Unsafe.Add(ref MemoryMarshal.GetReference(span), index);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref readonly T GetReference(this ReadOnlySpan span) => ref MemoryMarshal.GetReference(span);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref readonly T GetReference(this ReadOnlySpan span, int index) => ref Unsafe.Add(ref MemoryMarshal.GetReference(span), index);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref readonly T GetReference(this ReadOnlySpan span, nuint index) => ref Unsafe.Add(ref MemoryMarshal.GetReference(span), index);
+
+ /// Determines if a given reference to a value of type is not a null reference.
+ /// The type of the reference
+ /// The reference to check.
+ /// true if is not a null reference; otherwise, false.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsNotNullRef(in T source) => !IsNullRef(in source);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool IsNullRef(in T source) => Unsafe.IsNullRef(ref AsRef(in source));
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T NullRef() => ref Unsafe.NullRef();
+
+ ///
+ public static Span CreateSpan(ref T reference, int length) => MemoryMarshal.CreateSpan(ref reference, length);
+
+ ///
+ public static ReadOnlySpan CreateReadOnlySpan(in T reference, int length) => MemoryMarshal.CreateReadOnlySpan(ref AsRef(in reference), length);
+
+ /// Returns a pointer to the element of the span at index zero.
+ /// The type of items in .
+ /// The span from which the pointer is retrieved.
+ /// A pointer to the item at index zero of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T* GetPointer(this Span span)
+ where T : unmanaged => AsPointer(ref span.GetReference());
+
+ /// Returns a pointer to the element of the span at index zero.
+ /// The type of items in .
+ /// The span from which the pointer is retrieved.
+ /// A pointer to the item at index zero of .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T* GetPointer(this ReadOnlySpan span)
+ where T : unmanaged => AsPointer(ref AsRef(in span.GetReference()));
+}
diff --git a/src/samples/01-ClearScreen/Program.cs b/src/samples/01-ClearScreen/Program.cs
index c2c9401..8a83346 100644
--- a/src/samples/01-ClearScreen/Program.cs
+++ b/src/samples/01-ClearScreen/Program.cs
@@ -12,6 +12,9 @@ public static unsafe class Program
{
public static void Main()
{
+ string test = StringUtilities.GetString(new sbyte[] { (sbyte)'A', (sbyte)'B', (sbyte)'C' });
+ test = StringUtilities.GetString(new ushort[] { 'A', 'B', 'C' });
+
using ComPtr factory = default;
HResult hr = CreateDXGIFactory1(__uuidof(), (void**)&factory);
@@ -24,15 +27,34 @@ public static unsafe class Program
}
using ComPtr adapter = default;
+
+ using ComPtr factory6 = default;
+ if (factory.CopyTo(&factory6).Success)
+ {
+ for (uint adapterIndex = 0;
+ factory6.Get()->EnumAdapterByGpuPreference(
+ adapterIndex,
+ GpuPreference.HighPerformance,
+ __uuidof(),
+ (void**)adapter.ReleaseAndGetAddressOf()).Success;
+ adapterIndex++)
+ {
+ AdapterDescription1 desc = default;
+ adapter.Get()->GetDesc1(&desc);
+
+ string name = desc.DescriptionStr;
+ }
+ }
+
for (uint adapterIndex = 0;
factory.Get()->EnumAdapters1(adapterIndex, adapter.ReleaseAndGetAddressOf()).Success;
adapterIndex++)
{
AdapterDescription1 desc = default;
adapter.Get()->GetDesc1(&desc);
+
+ string name = desc.DescriptionStr;
}
-
-
}
[DllImport("dxgi", ExactSpelling = true)]