Skip to content

Latest commit

 

History

History
105 lines (63 loc) · 9.1 KB

robustness.adoc

File metadata and controls

105 lines (63 loc) · 9.1 KB

堅牢性

堅牢性とは

Vulkan アプリケーションが、アクセス権のないメモリにアクセス(ロード、ストア、アトミックの実行)しようとした場合、実装は何らかの反応をしなければなりません。堅牢性がない場合、それは未定義の動作であり、実装はプログラムを終了させることさえ許されます。アクセスするメモリの種類に対して堅牢性が有効になっている場合、実装は仕様で定義された特定の動作をしなければなりません。

robustness_flow.png

いつ使うのか

堅牢性を使用する一般的なケースは以下の通りである。

  1. 悪意のあるメモリーアクセスを防ぐ必要がある(例:WebGPU)。

  2. シェーダがアウトオブバウンズにならないことを保証できない。

  3. 他の場所で観察されたアウトオブバウンズ動作を模倣する。

Note
important

堅牢性を有効にすると、実行時パフォーマンスのコストが発生する場合があります。アプリケーションの作成者は、堅牢性を有効にするかどうかを慎重に検討する必要があります。

Vulkan がコアで提供するもの

すべての Vulkan の実装は robustBufferAccess 機能をサポートする必要があります。仕様では、何が境界を越えたとみなされるか、またどのように処理されるべきかが説明されています。robustBufferAccess については、実装にある程度の柔軟性が与えられています。たとえば、vec4(x,y,z,w) へのアクセスで w の値が境界を越えた場合、仕様では xyz も境界を越えたとみなすかどうかを実装が決定できるようになっています。

robustBufferAccess 機能は、バッファのみを対象としており、イメージは対象外であるため、いくつかの制限があります。また、アクセスされているバッファのデータを変更する境界を越えた書き込みやアトミックを許可してしまいます。より強力な堅牢性を求めるアプリケーションのために、VK_EXT_robustness2 があります。

イメージが境界を越えた場合、コア Vulkan では、ストアやアトミックがアクセスされるメモリに影響を与えないことが保証されています

robustBufferAccess

以下は、robustBufferAccessの使用例である。(オンラインで試す)

#version 450
layout(set = 0, binding = 0) buffer SSBO {
    // VkBufferは64バイトしかない。
    // [0:63]からのインデックスは有効で、残りはOOBです。
    uint data[128];
};

void main() {
    // 実行時にはOOBになります。
    // robustBufferAccessでは破棄されます。
    data[96] = 0;

    // robustBufferAccessではゼロを返す。
    uint x = data[127];
}

VK_EXT_image_robustness

robustImageAccess

VK_EXT_image_robustnessrobustImageAccess 機能は、イメージビューのサイズに対する境界を越えたアクセスをチェックします。イメージの境界をへのアクセスがあった場合、(0, 0, 0, 0) または (0, 0, 0, 1) を返します。

robustImageAccess 機能は、無効な LOD へのアクセスに対して返される値については何の保証もありません。

VK_EXT_robustness2

D3D12 などの他の API から移植されるアプリケーションなどでは、robustBufferAccessrobustImageAccess が提供するものよりも厳しい保証が必要になる場合があります。VK_EXT_robustness2 拡張機能では、以下のセクションで説明する3つの新しい堅牢性機能を公開することで、保証を追加しています。一部の実装では、これらの追加保証はパフォーマンスを犠牲にしています。追加の堅牢性を必要としないアプリケーションでは、可能な限り robustBufferAccessrobustImageAccess を代わりに使用することをお勧めします。

robustBufferAccess2

robustBufferAccess2 機能は robustBufferAccess のスーパーセットと見なすことができます。

この機能を有効にすると、境界を越えた書き込みやアトミックがバッファのメモリを変更することができなくなります。また、robustBufferAccess2 機能は、仕様書に記載されているように、境界を越えたアクセスしたときに、さまざまなタイプのバッファに対して返さなければならない値を強制的に設定します。

バッファが範囲チェックされる場所のアライメントは実装によって異なるため、VkPhysicalDeviceRobustness2PropertiesEXT から robustUniformBufferAccessSizeAlignment および robustStorageBufferAccessSizeAlignment をクエリすることが重要です。

robustImageAccess2

robustImageAccess2 機能は robustImageAccess のスーパーセットと見なすことができます。この機能は、アクセスしているイメージビューのサイズに対する境界を越えたかどうかのチェックをベースに、どのような値を返すことができるかについて、より厳しい要件を追加しています。

robustImageAccess2 では、R、RG、RGB フォーマットへの境界を越えたアクセスは (0, 0, 0, 1) を返します。VK_FORMAT_R8G8B8A8_UNORM のような RGBA フォーマットの場合は、(0, 0, 0, 0) を返します。

また、robustImageAccess2 を有効にして、サポートされていないイメージ LOD にアクセスした場合は、境界を越えたとみなされます。

nullDescriptor

nullDescriptor 機能が有効になっていない場合、VkDescriptorSet を更新するときには、たとえディスクリプタがシェーダで静的に使用されていなくても、対応するすべてのリソースは非ヌルでなければなりません。この機能により、ディスクリプタをヌルのリソースまたはビューと対応させることができます。ヌルディスクリプタからのロードはゼロ値を返し、ヌルディスクリプタへのストアとアトミックは破棄されます。

nullDescriptor 機能は、vkCmdBindVertexBuffers::pBuffers がヌルの場合にも、頂点入力バインディングへのアクセスを可能にします。

VK_EXT_pipeline_robustness

堅牢性は実装によってはパフォーマンスコストとなることがあるため、VK_EXT_pipeline_robustness 拡張が追加され、開発者は必要な部分のみ堅牢性を要求できるようになりました。

VkPipeline` の作成時に、1 つまたは複数の VkPipelineRobustnessCreateInfoEXT 構造体を渡すことで、パイプライン全体またはパイプラインステージ単位で、バッファ、イメージ、および頂点入力リソースへのアクセスの堅牢性動作を指定できます。

この拡張は、堅牢性機能が有効でない場合にデフォルトで提供される動作を実装に問い合わせる VkPhysicalDevicePipelineRobustnessPropertiesEXT も提供します。

VK_EXT_descriptor_indexing

VK_EXT_descriptor_indexing(Vulkan 1.2のコア)にあるバインド機能の後の更新を扱う場合は、実装が robustBufferAccess とディスクリプタのバインド後の更新機能の両方をサポートするかどうかを示す robustBufferAccessUpdateAfterBind を確認することが重要です。