.NET Оптимизация операций над массивом математических векторов с помощью SIMD - PullRequest
0 голосов
/ 04 июня 2019

Я разработал игру, в которой периодически добавляются векторы друг к другу. Например: position += movement; - это движение, которое выполняется на каждом такте игры для каждого юнита на игровом поле.

Вектор выглядит следующим образом, ofc с дополнительными методами:

public struct Vector
{
    public float X;
    public float Y;

    public Vector(float x, float y)
    {
        X = x;
        Y = y;
    }

    public static Vector operator +(Vector l, Vector r)
    {
        return new Vector(l.X + r.X, l.Y + r.Y);
    }
}

Я хочу максимально оптимизировать эти вычисления, потому что в игровом поле много таких единиц, и эти вычисления выполняются чаще, чем запрашивать значения векторов для других операций.

Моя идея теперь состоит в том, чтобы сохранить координаты X и Y в двух отдельных массивах для более быстрого расчета и собрать новые векторы из класса владельца или менеджера. Может быть, что-то вроде этого:

public class VectorHolder
{
    internal float[] x = new float[1024];
    internal float[] y = new float[1024];
    internal bool[] inUse = new bool[1024];

    public Vector NewVector()
    {
        return new Vector(this, aFreeSlotInTheArrays);
    }

    public void Add(VectorHolder holder)
    {
        int simdBlocks = Vector<float>.Count;

        for (int position = 0; position < 1024; position += simdBlocks)
        {
            (new Vector<float>(x, position) + new Vector<float>(holder.x, position)).CopyTo(x, position);
            (new Vector<float>(y, position) + new Vector<float>(holder.y, position)).CopyTo(y, position);
        }
    }
}

public struct Vector
{
    internal VectorHolder holder;
    internal int index;

    internal Vector(VectorHolder holder, int index)
    {
        this.holder = holder;
        this.index = index;
    }

    public float X => holder.x[index];
    public float Y => holder.y[index];

    public void Add(Vector vector)
    {
        holder.x[index] += vector.holder.x[vector.index];
        holder.y[index] += vector.holder.y[vector.index];
    }
}

Здесь можно добавить Vector из двух holder с (VectorHolder.Add) с очень высокой производительностью. Однако доступ к X или Y для Vector сейчас довольно медленный.

По моей идее, Вектор не будет хранить holder и position. Скорее, он будет хранить указатели на X и Y, так что мне не нужно будет напрямую обращаться к массивам держателей.

Однако я не знаю, как прикрепить (fixed) указатели к массивам навсегда, не делая их полем fixed с заранее определенной длиной. Кроме того, мой метод не очень хорош в долгосрочной перспективе, потому что память держателя будет фрагментирована, и поэтому инструкции SIMD будут снижаться в производительности, потому что будет также вычисляться все больше и больше пустых слотов Vector.

Мой вопрос сейчас такой: есть ли что-то подобное уже в .NET Framework или в NuGet, и я просто упустил это из виду? Что-то, что в лучшем случае также заботится о фрагментации и т. Д.? Если нет, как я могу закрепить память постоянно, чтобы я мог работать с ней, не вызывая fixed? У вас есть лучшее предложение для решения моей проблемы, чем мой подход?

Обратите внимание: код в этом вопросе является только псевдокодом, который может не работать, если вы скопируете его в IDE. Код только для лучшего понимания вопроса и, конечно, не будет с фиксированными значениями и т. Д. В реальной реализации.

...