Встроенное в Clang расширение матрицы и вектора: эффективное умножение матрицы на вектор

Я пишу небольшое графическое 3D-приложение, чтобы узнать о векторных и матричных расширениях Clang (матрицы все еще разрабатываются, если я читаю правильные версии документа ).

Я не уверен, как написать наиболее эффективный код для умножения матрицы на вектор, используя этот тип. С использованием:

      typedef float float4 __attribute__((ext_vector_type(4)));
typedef float m4x4 __attribute__((matrix_type(4, 4)));

В документе говорится (относительно индексов для доступа к элементам матрицы):

Первый указывает количество строк, а второй — количество столбцов.

           Column
        |
        v
Row->| M00 M01 M02 M03 |
     | M10 M11 M12 M13 |
     | M20 M21 M22 X23 |
     | M30 M31 M32 M33 |

Итак, я понимаю, что выполнение m[2][3] (где m — это m4x4) даст мне элемент, который я отметил X в матрице выше.

Затем (относительно того, как элементы расположены в памяти):

Элементы значения матричного типа располагаются по столбцам без заполнения.

Итак, из этой заметки я понял, что если бы я мог посмотреть, как элементы хранятся в памяти, я бы получил:

      M00 M10 M20 M30 - M01 M11 M21 M31 - M02 M12 M22 M32 - M03 M13 X23 M33 

Я правильно понял?

Имеет ли значение порядок, в котором мы обращаемся к элементам матрицы? (и правильно ли я делаю?)

Затем я предполагаю, что если бы я хотел быть эффективным в своем умножении mat-float4, мне нужно было бы получить доступ к элементам так, как они расположены в памяти, поэтому сделайте это:

      m4x3 m;
float4 v = {0.2, 0.3, 0.4, 1};
float4 res = {
    v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + v.w * m[3][0],
    v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + v.w * m[3][1],
    v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + v.w * m[3][2],
    1 // ignore w element for now
}

Конечно, я должен загрузить правильные значения в m[0][0], m[0][1],... используя что-то вроде __builtin_matrix_column_major_load.

Я слишком усложняю вещи, или здесь должен иметь значение порядок. Действительно ли приведенное выше уравнение лучше, чем:

      float4 res = {
    v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],
    v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3],
    v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3],
    1 // ignore w element for now
}

(при условии, что я переставил элементы перед вызовом__builtin_matrix_column_major_load.

Есть ли лучший способ сделать это?

Теперь я понимаю, что эти типы разрабатываются в данный момент. Тем не менее, я понимаю, что весь смысл этих типов в том, чтобы воспользоваться SIMD-инструкциями. Если я сделаю:

      float4 a = {...};
float4 b = {...};
float4 c = a + b;

Затем добавьте 4 поплавкаaк соответствующим 4 поплавкамbпроисходит в одном цикле? Итак, что касается умножения mat-float4, поскольку я вызываю элементы float4 и m4x4 по отдельности в своем коде, кажется, что в этом конкретном случае я не воспользуюсь преимуществами какой-либо оптимизации?

Итак, мой второй вопрос: есть ли лучший способ сделать это?

  • Должен ли я хранить матричные векторы в 4 float4 и вместо этого выполнять умножение float4 * float4?
  • Я видел этот пост Умножение матрицы-вектора и матрицы-матрицы с использованием SSE , в котором приводится пример того, как добиться умножения мат-вектора с использованием инструкций SIMD. Кажется, это позволяет складывать элементы матрицы в__m128и используйте их, чтобы получить элементы матрицы, умноженные на элементы вектора, используя дополнительные инструкции SIMD, такие как_mm_add_psиmm_mul_ps.
  • Должен ли я просто ждать, пока эта разработка станет более зрелой?

Любая обратная связь или совет будут очень признательны. Я делаю это как упражнение, чтобы узнать об этих новых встроенных типах.

0 ответов

Другие вопросы по тегам