Внутренние компоненты библиотек
В этом разделе описывается внутренняя конструкция библиотеки DirectXMath.
- Соглашения о вызовах
- Эквивалентность типов графической библиотеки
- Глобальные константы в библиотеке DirectXMath
- Windows SSE и SSE2
- Стандартные варианты
- Несоответствия платформы
- Расширения для конкретной платформы
- Связанные статьи
Соглашения о вызовах
Чтобы повысить переносимость и оптимизировать макет данных, необходимо использовать соответствующие соглашения о вызовах для каждой платформы, поддерживаемой библиотекой DirectXMath. В частности, при передаче объектов XMVECTOR в качестве параметров, которые определяются как выровненные по границе 16-байтов, существуют различные наборы требований к вызову в зависимости от целевой платформы:
Для 32-разрядных Windows
Для 32-разрядной версии Windows существует два соглашения о вызовах, доступных для эффективного передачи значений __m128 (реализующих XMVECTOR на этой платформе). Стандартом является __fastcall, который может передавать первые три __m128 значения (экземпляры XMVECTOR ) в качестве аргументов функции в регистре SSE/SSE2 . __fastcall передает оставшиеся аргументы через стек.
Более новые компиляторы Microsoft Visual Studio поддерживают новое соглашение о вызовах, __vectorcall, которое может передавать до шести __m128 значений (экземпляры XMVECTOR) в качестве аргументов функции в регистре SSE/SSE2. Он также может передавать разнородные агрегаты векторов (также известные как XMMATRIX) через регистры SSE/SSE2, если достаточно места.
Для 64-разрядных выпусков Windows
Для 64-разрядной версии Windows существует два соглашения о вызовах, доступные для эффективного передачи значений __m128 . Стандарт __fastcall, который передает все __m128 значения в стеке.
Более новые компиляторы Visual Studio поддерживают соглашение о вызове __vectorcall, которое может передавать до шести __m128 значений (экземпляров XMVECTOR) в качестве аргументов функции в регистре SSE/SSE2. Он также может передавать разнородные агрегаты векторов (также известные как XMMATRIX) через регистры SSE/SSE2, если достаточно места.
Для Windows в ARM
Windows в ARM и ARM64 поддерживает передачу первых четырех __n128 значений (экземпляров XMVECTOR ) в регистре.
Решение DirectXMath
Псевдонимы FXMVECTOR, GXMVECTOR, HXMVECTOR и CXMVECTOR поддерживают следующие соглашения:
- Используйте псевдоним FXMVECTOR для передачи до первых трех экземпляров XMVECTOR, используемых в качестве аргументов функции.
- Используйте псевдоним GXMVECTOR для передачи 4-го экземпляра XMVECTOR, используемого в качестве аргумента функции.
- Используйте псевдоним HXMVECTOR для передачи 5-го и 6-го экземпляров XMVECTOR, используемых в качестве аргумента функции. Дополнительные сведения см. в документации по __vectorcall.
- Используйте псевдоним CXMVECTOR для передачи всех дополнительных экземпляров XMVECTOR, используемых в качестве аргументов.
Примечание.
Для выходных параметров всегда используйте XMVECTOR* или XMVECTOR& и игнорируйте их в отношении предыдущих правил входных параметров.
Из-за ограничений __vectorcall рекомендуется не использовать GXMVECTOR или HXMVECTOR для конструкторов C++. Просто используйте FXMVECTOR для первых трех значений XMVECTOR, а затем используйте CXMVECTOR для остальных.
Псевдонимы FXMMATRIX и CXMMATRIX помогают использовать преимущества аргумента HVA, передаваемого __vectorcall.
- Используйте псевдоним FXMMATRIX, чтобы передать первый XMMATRIX в качестве аргумента функции. Предполагается, что у вас нет более двух аргументов FXMVECTOR или более двух аргументов float, double или FXMVECTOR вправо матрицы. Дополнительные сведения см. в документации по __vectorcall.
- В противном случае используйте псевдоним CXMMATRIX.
Из-за ограничений __vectorcall рекомендуется никогда не использовать конструкторы FXMMATRIX для C++. Просто используйте CXMMATRIX.
Помимо псевдонимов типов, необходимо также использовать заметку XM_CALLCONV, чтобы убедиться, что функция использует соответствующее соглашение о вызовах (__fastcall и __vectorcall) на основе компилятора и архитектуры. Из-за ограничений __vectorcall рекомендуется не использовать XM_CALLCONV для конструкторов C++.
Ниже приведены примеры объявлений, которые иллюстрируют это соглашение:
XMMATRIX XM_CALLCONV XMMatrixLookAtLH(FXMVECTOR EyePosition, FXMVECTOR FocusPosition, FXMVECTOR UpDirection);
XMMATRIX XM_CALLCONV XMMatrixTransformation2D(FXMVECTOR ScalingOrigin, float ScalingOrientation, FXMVECTOR Scaling, FXMVECTOR RotationOrigin, float Rotation, GXMVECTOR Translation);
void XM_CALLCONV XMVectorSinCos(XMVECTOR* pSin, XMVECTOR* pCos, FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVectorHermiteV(FXMVECTOR Position0, FXMVECTOR Tangent0, FXMVECTOR Position1, GXMVECTOR Tangent1, HXMVECTOR T);
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3)
XMVECTOR XM_CALLCONV XMVector2Transform(FXMVECTOR V, FXMMATRIX M);
XMMATRIX XM_CALLCONV XMMatrixMultiplyTranspose(FXMMATRIX M1, CXMMATRIX M2);
Для поддержки этих соглашений о вызовах эти псевдонимы типов определяются следующим образом (параметры должны передаваться по значению компилятору, чтобы рассмотреть их для передачи в регистре):
Для 32-разрядных приложений Windows
При использовании __fastcall:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
При использовании __vectorcall:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Для 64-разрядных собственных приложений Windows
При использовании __fastcall:
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& GXMVECTOR;
typedef const XMVECTOR& HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
При использовании __vectorcall:
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR HXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Windows на архитектуре ARM
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR GXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
typedef const XMMATRIX& FXMMATRIX;
typedef const XMMATRIX& CXMMATRIX;
Примечание.
Хотя все функции объявляются встроенными, и во многих случаях компилятору не нужно использовать соглашения о вызовах для этих функций, существуют случаи, когда компилятор может решить, что это более эффективно, чтобы не встраивать функцию, и в этих случаях мы хотим лучшего соглашения о вызовах для каждой платформы.
Эквивалентность типов графической библиотеки
Для поддержки использования библиотеки DirectXMath многие типы и структуры библиотек DirectXMath эквивалентны реализации D3DDECLTYPE и D3DFORMAT типов Windows, а также типов DXGI_FORMAT.
DirectXMath | D3DDECLTYPE | D3DFORMAT | DXGI_FORMAT |
---|---|---|---|
XMBYTE2 | DXGI_FORMAT_R8G8_SINT | ||
XMBYTE4 | D3DDECLTYPE_BYTE4 (только Xbox) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SINT |
XMBYTEN2 | D3DFMT_V8U8 | DXGI_FORMAT_R8G8_SNORM | |
XMBYTEN4 | D3DDECLTYPE_BYTE4N (только Xbox) | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_SNORM |
XMCOLOR | D3DDECLTYPE_D3DCOLOR | D3DFMT_A8R8G8B8 | DXGI_FORMAT_B8G8R8A8_UNORM (DXGI 1.1+) |
XMDEC4 | D3DDECLTYPE_DEC4 (только Xbox) | D3DDECLTYPE_DEC3 (только Xbox) | |
XMDECN4 | D3DDECLTYPE_DEC4N (только Xbox) | D3DDECLTYPE_DEC3N (только Xbox) | |
XMFLOAT2 | D3DDECLTYPE_FLOAT2 | D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
XMFLOAT2A | D3DDECLTYPE_FLOAT2 | D3DFMT_G32R32F | DXGI_FORMAT_R32G32_FLOAT |
XMFLOAT3 | D3DDECLTYPE_FLOAT3 | DXGI_FORMAT_R32G32B32_FLOAT | |
XMFLOAT3A | D3DDECLTYPE_FLOAT3 | DXGI_FORMAT_R32G32B32_FLOAT | |
XMFLOAT3PK | DXGI_FORMAT_R11G11B10_FLOAT | ||
XMFLOAT3SE | DXGI_FORMAT_R9G9B9E5_SHAREDEXP | ||
XMFLOAT4 | D3DDECLTYPE_FLOAT4 | D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
XMFLOAT4A | D3DDECLTYPE_FLOAT4 | D3DFMT_A32B32G32R32F | DXGI_FORMAT_R32G32B32A32_FLOAT |
XMHALF2 | D3DDECLTYPE_FLOAT16_2 | D3DFMT_G16R16F | DXGI_FORMAT_R16G16_FLOAT |
XMHALF4 | D3DDECLTYPE_FLOAT16_4 | D3DFMT_A16B16G16R16F | DXGI_FORMAT_R16G16B16A16_FLOAT |
XMINT2 | DXGI_FORMAT_R32G32_SINT | ||
XMINT3 | DXGI_FORMAT_R32G32B32_SINT | ||
XMINT4 | DXGI_FORMAT_R32G32B32A32_SINT | ||
XMSHORT2 | D3DDECLTYPE_SHORT2 | D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SINT |
XMSHORTN2 | D3DDECLTYPE_SHORT2N | D3DFMT_V16U16 | DXGI_FORMAT_R16G16_SNORM |
XMSHORT4 | D3DDECLTYPE_SHORT4 | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_SINT |
XMSHORTN4 | D3DDECLTYPE_SHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_SNORM |
XMUBYTE2 | DXGI_FORMAT_R8G8_UINT | ||
XMUBYTEN2 | D3DFMT_A8P8, D3DFMT_A8L8 | DXGI_FORMAT_R8G8_UNORM | |
XMUINT2 | DXGI_FORMAT_R32G32_UINT | ||
XMUINT3 | DXGI_FORMAT_R32G32B32_UINT | ||
XMUINT4 | DXGI_FORMAT_R32G32B32A32_UINT | ||
XMU555 | D3DFMT_X1R5G5B5, D3DFMT_A1R5G5B5 | DXGI_FORMAT_B5G5R5A1_UNORM | |
XMU565 | D3DFMT_R5G6B5 | DXGI_FORMAT_B5G6R5_UNORM | |
XMUBYTE4 | D3DDECLTYPE_UBYTE4 | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_UINT |
XMUBYTEN4 | D3DDECLTYPE_UBYTE4N | D3DFMT_x8x8x8x8 | DXGI_FORMAT_x8x8x8x8_UNORM DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM (использование XMLoadUDecN4_XR и XMStoreUDecN4_XR.) |
XMUDEC4 | D3DDECLTYPE_UDEC4 (только Xbox) D3DDECLTYPE_UDEC3 (только Xbox) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UINT |
XMUDECN4 | D3DDECLTYPE_UDEC4N (только Xbox) D3DDECLTYPE_UDEC3N (только Xbox) |
D3DFMT_A2R10G10B10 D3DFMT_A2B10G10R10 |
DXGI_FORMAT_R10G10B10A2_UNORM |
XMUNIBBLE4 | D3DFMT_A4R4G4B4, D3DFMT_X4R4G4B4 | DXGI_FORMAT_B4G4R4A4_UNORM (DXGI 1.2+) | |
XMUSHORT2 | D3DDECLTYPE_USHORT2 | D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UINT |
XMUSHORTN2 | D3DDECLTYPE_USHORT2N | D3DFMT_G16R16 | DXGI_FORMAT_R16G16_UNORM |
XMUSHORT4 | D3DDECLTYPE_USHORT4 (только Xbox) | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UINT |
XMUSHORTN4 | D3DDECLTYPE_USHORT4N | D3DFMT_x16x16x16x16 | DXGI_FORMAT_R16G16B16A16_UNORM |
Глобальные константы в библиотеке DirectXMath
Чтобы уменьшить размер сегмента данных, библиотека DirectXMath использует макрос XMGLOBALCONST для использования ряда глобальных внутренних констант в реализации. По соглашению такие внутренние глобальные константы префиксируются g_XM. Как правило, они являются одним из следующих типов: XMVECTORU32, XMVECTORF32 или XMVECTORI32.
Эти внутренние глобальные константы могут изменяться в будущих редакциях библиотеки DirectXMath. Используйте общедоступные функции, которые инкапсулируют константы, если это возможно, а не прямое использование g_XM глобальных значений. Вы также можете объявить собственные глобальные константы с помощью XMGLOBALCONST.
Windows SSE и SSE2
Набор инструкций SSE предоставляет поддержку только для векторов с плавающей запятой с одной точностью. DirectXMath должен использовать набор инструкций SSE2, чтобы обеспечить поддержку целочисленных векторов. SSE2 поддерживается всеми процессорами Intel с момента внедрения Процессоров Intel 4, всех процессоров AMD K8 и более поздних версий, а также всех процессоров с поддержкой x64.
Примечание.
Для Windows 8 для x86 или более поздней версии требуется поддержка SSE2. Для всех версий Windows x64 требуется поддержка SSE2. Для Windows в ARM или ARM64 требуется ARM_NEON.
Стандартные варианты
Существует несколько вариантов функций DirectXMath, которые упрощают работу:
- Функции сравнения для создания сложной условной ветви на основе меньшего числа операций сравнения векторов. Имя этих функций заканчивается на "R", например XMVector3InBoundsR. Функции возвращают запись сравнения как возвращаемое значение UINT или как параметр UINT out. Для проверки значения можно использовать макросы XMComparision* .
- Пакетные функции для выполнения операций с пакетным стилем для больших массивов векторов. Имя этих функций заканчивается в потоке, например XMVector3TransformStream. Функции работают с массивом входных данных и создают массив выходных данных. Как правило, они принимают входные и выходные шаги.
- Функции оценки, реализующие более быструю оценку, а не более медленный, более точный результат. Имя этих функций заканчивается на "Est", например XMVector3NormalizeEst. Влияние на качество и производительность оценки зависит от платформы до платформы, но рекомендуется использовать варианты оценки для кода с учетом производительности.
Несоответствия платформы
Библиотека DirectXMath предназначена для использования в приложениях и играх с учетом производительности. Поэтому реализация предназначена для оптимальной скорости нормальной обработки на всех поддерживаемых платформах. Результаты в условиях границы, особенно те, которые создают специальные элементы с плавающей запятой, скорее всего, зависят от целевого объекта до целевого. Это поведение также будет зависеть от других параметров времени выполнения, таких как слово элемента управления x87 для целевого объекта Windows 32-разрядной версии без встроенных функций или слово элемента управления SSE для Windows 32-разрядной и 64-разрядной версии. Кроме того, существуют различия в условиях границ между различными поставщиками ЦП.
Не используйте DirectXMath в научных или других приложениях, где числовая точность является первостепенной. Кроме того, это ограничение отражается в отсутствии поддержки двойного или другого расширенных вычислений точности.
Примечание.
_XM_NO_INTRINSICS_ скалярные пути кода обычно записываются для соответствия требованиям, а не производительности. Их результаты условия границы также будут отличаться.
Расширения для конкретной платформы
Библиотека DirectXMath предназначена для упрощения программирования С++ SIMD, обеспечивая отличную поддержку платформ x86, x64 и Windows RT, используя широко поддерживаемые встроенные инструкции (SSE2 и ARM-NEON).
Однако есть времена, когда инструкции для конкретной платформы могут оказаться полезными. Благодаря реализации DirectXMath во многих случаях для использования типов DirectXMath непосредственно в стандартных встроенных инструкциях компилятора и использовать DirectXMath в качестве резервного пути для платформ, которые не поддерживают расширенную инструкцию.
Например, ниже приведен упрощенный пример использования инструкции SSE 4.1 dot-product. Обратите внимание, что необходимо явно защитить путь к коду, чтобы избежать создания недопустимых исключений инструкций во время выполнения. Убедитесь, что пути кода выполняют достаточную работу, чтобы оправдать дополнительные затраты на ветвление, сложность обслуживания нескольких путей кода и т. д.
#include <Windows.h>
#include <stdio.h>
#include <DirectXMath.h>
#include <intrin.h>
#include <smmintrin.h>
using namespace DirectX;
bool g_bSSE41 = false;
void DetectCPUFeatures()
{
#ifndef _M_ARM
// See __cpuid documentation for more information
int CPUInfo[4] = {-1};
#if defined(__clang__) || defined(__GNUC__)
__cpuid(0, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#else
__cpuid(CPUInfo, 0);
#endif
if ( CPUInfo[0] >= 1 )
{
#if defined(__clang__) || defined(__GNUC__)
__cpuid(1, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
#else
__cpuid(CPUInfo, 1);
#endif
if ( CPUInfo[2] & 0x80000 )
g_bSSE41 = true;
}
#endif
}
int main()
{
if ( !XMVerifyCPUSupport() )
return -1;
DetectCPUFeatures();
...
XMVECTORF32 v1 = { 1.f, 2.f, 3.f, 4.f };
XMVECTORF32 v2 = { 5.f, 6.f, 7.f, 8.f };
XMVECTOR r2, r3, r4;
if ( g_bSSE41 )
{
#ifndef _M_ARM
r2 = _mm_dp_ps( v1, v2, 0x3f );
r3 = _mm_dp_ps( v1, v2, 0x7f );
r4 = _mm_dp_ps( v1, v2, 0xff );
#endif
}
else
{
r2 = XMVector2Dot( v1, v2 );
r3 = XMVector3Dot( v1, v2 );
r4 = XMVector4Dot( v1, v2 );
}
...
return 0;
}
Дополнительные сведения о расширениях для конкретной платформы см. в следующем разделе:
DirectXMath: SSE, SSE2 и ARM-NEON
DirectXMath: SSE3 и SSSE3
DirectXMath: SSE4.1 и SSE4.2
DirectXMath: AVX
DirectXMath: F16C и FMA
DirectXMath: AVX2
DirectXMath: ARM64