//----------------------------------------------------------------------- // ----------------------------------------------------------------------- // file="MatrixPanel" // Project: StgSharp // AuthorGroup: Nitload // Copyright (c) Nitload. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- using StgSharp.Internal; using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace StgSharp.HighPerformance { public unsafe struct MatrixPanel { private byte Head; } // Single POD-style panel: ZMM-compatible size. Alignment handled by allocator, not by the struct. public unsafe struct MatrixPanel where T : unmanaged, INumber { public const int AlignmentBytes = 64; internal T Head; // first element of the panel buffer public ref T this[int column, int row] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref Unsafe.Add(ref Head, row * ElementSideLength + column); } public static int ElementSideLength { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Math.Max(8, AlignmentBytes / sizeof(T)); } public static int MaxElementCount { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ElementSideLength * ElementSideLength; } public static nuint Size { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => (nuint)(MaxElementCount * sizeof(T)); } public Span Elements { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { ref T first = ref Head; unsafe { void* p = Unsafe.AsPointer(ref first); return new Span(p, MaxElementCount); } } } // Allocate aligned memory for one panel; caller must free via Destroy. public static unsafe MatrixPanel* Create() { return (MatrixPanel*)NativeMemory.AlignedAlloc(Size, AlignmentBytes); } public static unsafe void Destroy(MatrixPanel* panel) { NativeMemory.AlignedFree(panel); } // View an existing pointer; caller guarantees lifetime/alignment. public static unsafe MatrixPanel* FromPointer(void* ptr) { return (MatrixPanel*)Align64(ptr); } /// /// Number of 4x4 kernels that fit in a panel for the given ISA and element T. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int KernelCapacity() { int perSide = KernelSideCount(); return perSide * perSide; } /// /// How many 4x4 kernels fit along a single panel dimension for the given ISA. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int KernelSideCount() { return NativeIntrinsic.IntrinsicLevel switch { IntrinsicLevel.SSE => KernelSideCountSse(), IntrinsicLevel.AVX2 => KernelSideCountAvx2(), IntrinsicLevel.AVX512 => KernelSideCountAvx512(), _ => 0 }; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static unsafe nuint Align64(void* p) => ((nuint)p + (AlignmentBytes - 1)) & ~(nuint)(AlignmentBytes - 1); [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int KernelSideCountAvx2() { const int minQ = 8; int lanes = 32 / sizeof(T); int side = Math.Max(lanes, minQ); return side / 4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int KernelSideCountAvx512() { const int minQ = 8; int lanes = 64 / sizeof(T); int side = Math.Max(lanes, minQ); return side / 4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int KernelSideCountSse() { const int minQ = 4; int lanes = 16 / sizeof(T); int side = Math.Max(lanes, minQ); return side / 4; } } }