Написание вычислительных шейдеров для нескольких платформ
Передовые методы работы с различными платформами
DirectX 11 (DX11) и DirectX 12 (DX12) поддерживают многие действия, которые не поддерживаются на других платформах (таких как Metal или OpenGL ES). Поэтому вы всегда должны убедиться, что ваш шейдер имеет хорошо определенное поведение на платформах, которые предлагают меньшую поддержку, а не только на DX11 или DX12. Вот несколько вещей, которые следует учитывать:
DX11 может последовательно возвращать нуль при чтении и читать некоторые записи без проблем, но платформы, которые предлагают меньшую поддержку, могут сбить GPU при этом. Остерегайтесь DX11-специфических хаков, размеров буфера, не соответствующих кратным размера группы потоков, попыток чтения соседних элементов данных из начала или конца буфера и подобных несовместимостей.
Инициализируйте ресурсы. Содержимое новых буферов и Текстур не определено. Некоторые платформы могут предоставлять все нули, но на других, может быть что угодно, включая NaNs.
Привяжите все ресурсы, которые объявляет ваш вычислительный шейдер. Даже если вы уверены, что из-за ветвления шейдер не использует ресурс в текущем состоянии, вы всё равно должны позаботиться, чтобы ресурс был к нему привязан.
Различия между платформами
- Metal (для платформ iOS и tvOS) не поддерживает атомарные операции на Текстурах. Metal также не поддерживает запросы
GetDimensionsна буферы. Передаёт информацию о размере буфера как константу шейдеру, если это необходимо. - OpenGL ES 3.1 (для платформ (Android, iOS, tvOS) гарантирует поддержку только 4 вычислительных буферов одновременно. Реальные реализации обычно поддерживают больше, но в целом, если вы разрабатываете для OpenGL ES, вы должны рассмотреть возможность группирования связанных данных в структуры, а не иметь каждый элемент данных в отдельном буфере.
- OpenGL (ES) и Vulkan требуют квалификатора формата изображения для
RWTextures<T>, который не является только для записи.
Unity получает этот квалификатор от типа T в квадратных скобках. Квалификатор формата должен соответствовать GraphicsFormat/RenderTextureFormat из RenderTexture, который связан с RWTexture. В следующей таблице Unity RenderTexture GraphicsFormats и RenderTextureFormats сопоставлены с их соответствующими квалификаторами типа и формата изображения HLSL:
| GraphicsFormat | RenderTextureFormat | Тип HLSL | GLSL квалификационный параметр формата изображения |
|---|---|---|---|
| R32G32B32A32_SFloat | ARGBFloat | float4 (плавающий) | rgba32f |
| R16G16B16A16_SFloat | ARGBHalf | min16float4/half4 | rgba16f |
| R32G32_SFloat | RGFloat | float2 (плавающий) | rg32f |
| R16G16_SFloat | RGHalf | min16float2/half2 | rg16f |
| B10G11R11_UFloatPack32 | RGB111110Float | min10float3 | r11f_g11f_b10f |
| R32_SFloat | RFloat | поплавок | r32f |
| R16_SFloat | RHalf | min16float/половина | r16f |
| R16G16B16A16_UNorm | ARGB64 | ненормальный min16float4/half4 | rgba16 |
| A2B10G10R10_UNormPack32 | ARGB2101010 | ненормальный min10float4 | rgb10_a2 |
| R8G8B8A8_UNorm | ARGB32 | ненормальный float4 | rgba8 |
| R16G16_UNorm | RG32 | ненормальный min16float2/half2 | rg16 |
| R8G8_UNorm | RG16 | ненормальный float2 | rg8 |
| R16_UNorm | R16 | ненормальный min16float/половина | r16 |
| R8_UNorm | R8 | ненормированный поплавок | r8 |
| R16G16B16A16_SNorm | не поддерживается | снорм min16float4/half4 | rgba16_snorm |
| R8G8B8A8_SNorm | не поддерживается | снорм float4 | rgba8_snorm |
| R16G16_SNorm | не поддерживается | снорм min16float2/half2 | rg16_snorm |
| R8G8_SNorm | не поддерживается | снорм float2 | rg8_snorm |
| R16_SNorm | не поддерживается | снорм min16float/половина | r16_snorm |
| R8_SNorm | не поддерживается | снорм поплавок | r8_snorm |
| R32G32B32A32_SInt | ARGBInt | int4 | rgba32i |
| R16G16B16A16_SInt | не поддерживается | min16int4 | rgba16i |
| R8G8B8A8_SInt | не поддерживается | min12int4 | rgba8i |
| R32G32_SInt | RGInt | int2 (полное число) | rg32i |
| R16G16_SInt | не поддерживается | min16int2 | rg16i |
| R8G8_SInt | не поддерживается | min12int2 | rg8i |
| R32_SInt | RInt | инт | r32i |
| R16_SInt | не поддерживается | min16int | r16i |
| R8_SInt | не поддерживается | min12int | r8i |
| R32G32B32A32_UInt | не поддерживается | uint4 | rgba32i |
| R16G16B16A16_UInt | RGBAUShort | min16uint4 | rgba16ui |
| R8G8B8A8_UInt | не поддерживается | не поддерживается | rgba8ui |
| R32G32_UInt | не поддерживается | uint2 | rg32ui |
| R16G16_UInt | не поддерживается | min16uint2 | rg16ui |
| R8G8_UInt | не поддерживается | не поддерживается | rg8ui |
| R32_UInt | не поддерживается | УИНТ | r32ui |
| R16_UInt | не поддерживается | min16uint | r16ui |
| R8_UInt | не поддерживается | не поддерживается | r8ui |
| A2B10G10R10_UIntPack32 | не поддерживается | не поддерживается | rgb10_a2ui |