実装がインターフェイスからメモリにアクセスするとき、メモリレイアウトを知る必要があります。これには、オフセット、ストライド、 アライメントが含まれます。Vulkan Spec には レイアウトのセクション がありますが、さまざまな拡張機能による複雑化により、理解が困難な場合があります。この章では、いくつかの高レベルシェーディング言語(GLSL)の例を用いて、Vulkan が使用するすべてのメモリレイアウトの概念を説明します。
Vulkan には、インターフェイスオブジェクトをレイアウトできる3つのアライメント要件があります。
-
拡張アライメント (別名
std140
) -
ベースアライメント (別名
std430
) -
スカラアライメント
アライメントに関する仕様言語では、以下のブロックメンバ型ごとにルールを分解しています。
-
scalar (
float
,int
,char
, 等) -
vector (
float2
,vec3
,uvec4
, 等) -
matrix
-
array
-
struct
Note
|
Vulkan 1.2でコアに昇格 |
この拡張機能により、UBOで std430
メモリレイアウトを使用できるようになります。
Vulkan Standard Buffer Layout Interfaceは、このガイドには含まれていません。プッシュ定数や SSBO など、他のストレージアイテムはすでに std430 スタイルのレイアウトが可能なため、これらのメモリレイアウトの変更は Uniforms
にのみ適用されます。
UniformBufferStandardLayout
機能が必要な場合の一例として、アプリケーションが UBO の配列のストライドを extended alignment
に制限したくない場合があります。
(オンラインで試す)
layout(std140, binding = 0) uniform ubo140 {
float array140[8];
};
layout(std430, binding = 1) uniform ubo430 {
float array430[8];
};
SPIR-V では次のようになります。
// 配列の拡張アライメントは、16の倍数に切り上げられます。
OpDecorate %array140 ArrayStride 16
// ベースアライメントは 4 バイト(OpTypeFloat32)
// uniformBufferStandardLayout 機能が有効な場合のみ有効
OpDecorate %array430 ArrayStride 4
SPIR-V Validator を実行する際には、必ず --uniform-buffer-standard-layout
を設定してください。
Note
|
Vulkan 1.1でコアに昇格 この拡張機能のために機能ビットが追加されることはなかったため、Vulkan 1.1以上のすべてのデバイスがリラックスブロックレイアウトをサポートしています。 |
この拡張機能により、ブロックの Offset
修飾のバリエーションの対応を実装で示すことができます。これは std430
メモリレイアウトを使用する際に出てくるもので、通常 vec3
(12バイト) は16バイトのアライメントとして定義されています。リラックスブロックレイアウトでは、アプリケーションは vec3
の両側に float
を置くことができ、それらの間の 16 バイトのアライメントを維持することができます。
// リラックスブロックレイアウトを使わない場合の SPIR-V のオフセット
layout (set = 0, binding = 0) buffer block {
float b; // Offset: 0
vec3 a; // Offset: 16
} ssbo;
// リラックスブロックレイアウトを使う場合の SPIR-V のオフセット
layout (set = 0, binding = 0) buffer block {
float b; // Offset: 0
vec3 a; // Offset: 4
} ssbo;
VK_KHR_relaxed_block_layout
は VK_EXT_scalar_block_layout
のサブセットとみなすこともできます。
Note
|
Vulkan 1.0 環境を使用して SPIR-V Validator を実行する場合は、必ず |
Note
|
現在のところ、GLSL にはリラックスブロックレイアウトを正式に表現する方法はありませんが、 |
Note
|
Vulkan 1.2でコアに昇格 |
この拡張機能により、ほとんどのストレージ型が scalar alignment
でアライメントされるようになります。大きな違いは、16バイトの境界をまたぐことができることです。
GLSL では、これは scalar
キーワードと拡張機能で使うことができます。
#extension GL_EXT_scalar_block_layout : enable
layout (scalar, binding = 0) buffer block { }
Note
|
SPIR-V Validator を実行する際には、必ず |
Note
|
|
以下は、サポートするアライメントの違いをより理解するための GLSL から SPIR-V への変換例です。
(オンラインで試す)
layout(binding = 0) buffer block {
vec2 a[4];
vec4 b;
};
SPIR-V では次のようになります。
// 拡張アライメント (std140)
OpDecorate %vec2array ArrayStride 16
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 64
// スカラアライメントとベースアライメント (std430)
OpDecorate %vec2array ArrayStride 8
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 32
(オンラインで試す)
layout(binding = 0) buffer block {
float a;
vec2 b;
vec2 c;
};
SPIR-V では次のようになります。
// 拡張アライメント (std140) とベースアライメント (std430)
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 8
OpMemberDecorate %block 2 Offset 16
// スカラアライメント
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 4
OpMemberDecorate %block 2 Offset 12
(オンラインで試す)
layout(binding = 0) buffer block {
vec3 a;
vec2 b;
vec4 c;
};
SPIR-V では次のようになります。
// 拡張アライメント (std140) とベースアライメント (std430)
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 16
OpMemberDecorate %block 2 Offset 32
// スカラアライメント
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 12
OpMemberDecorate %block 2 Offset 20
(オンラインで試す)
layout (binding = 0) buffer block {
vec3 a;
vec2 b;
vec2 c;
vec3 d;
};
SPIR-V では次のようになります。
// 拡張アライメント (std140) とベースアライメント (std430)
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 16
OpMemberDecorate %block 2 Offset 24
OpMemberDecorate %block 3 Offset 32
// スカラアライメント
OpMemberDecorate %block 0 Offset 0
OpMemberDecorate %block 1 Offset 12
OpMemberDecorate %block 2 Offset 20
OpMemberDecorate %block 3 Offset 28