Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

GL_EXT_scalar_block_layoutについて

概要

Vulkan + Ray Tracingのコードを書き始めたときから気になっていたGL_EXT_scalar_block_layoutの拡張機能について調べてみた。

GL_EXT_scalar_block_layoutについて

仕様書はこちら
GLSL/GL_EXT_scalar_block_layout.txt at master · KhronosGroup/GLSL · GitHub

vulkanのray tracingでも見たことがあるような感じで、GitHubにテキストが置かれているだけの仕様書となっている。

OpenGL Shading Language Specificationを参照する形式で記述されていので、こちらも見ながら仕様書を読む必要がある。
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf

Requirement

仕様書には、以下のように書かれている。

  • Written against SPIR-V 1.3.
  • Written against GLSL 4.6.
  • Written against Vulkan 1.1 with the VK_EXT_scalar_block_layout extension.

「この仕様書は~に対して書かれる」といった書かれ方だが、素直に上記のバージョンが必要であると読んでよさそう。

Overview

Adds a new block layout (scalar) for uniform, push constant, and storage
buffer blocks.
This new layout aligns values only to the scalar components of the block
and its composite members.

Additionally, this extension now allows uniform blocks to be decorated
with the std430 layout.

GL_EXT_scalar_block_layoutの拡張機能の肝は新しいblock layoutの追加であり、
そのblock layoutの追加はuniform, push constant, and storage buffer blocksに対して行われる。

またuniform blocksがstd430 layoutで修飾されていてもOKとある。

詳細

Section 4.4

表の1行目の1セルにscalarを追加とあるので、以下のようになる。

Layout Qualifier Qualifier Only Individual Variables Block Block Member Allowed Interfaces
shared
packed
std140
std430
scalar
X X uniform /
buffer

Section 4.4.5

Such a structure and each structure member have a base offset
and a base alignment, from which an aligned offset is computed
by rounding the base offset up to a multiple of the base
alignment.

scalerの修飾子をつけたuniformやbufferのoffsetやalignmentを定義しており、offsetとalignmentのルールはvulkanとのinterfaceで定めている内容に沿っている。

具体例の考察

#extension GL_EXT_scalar_block_layout : enable
layout(binding = 3, set = 0, scalar) buffer Vertices {Vertex3D v[];} vertices[];

例えば上記のようにglslシェーダの中に記述できる。
拡張機能の有効化によりlayout修飾子にscalarが追加されたので、layout()内でscalarを宣言できる。

bufferのメンバーはVertex3Dというユーザ定義の構造体である。
この場合

5. If the member is a structure, the base alignment of the structure is
N, where N is the largest base alignment value of any of its members.

とあり、最大のalignmentとなる要素がvec4であったとすれば、base alignmentはvec4のものとなる。
base alignmentが決まればaligned offsetも決まるため、そこからbase offsetもおそらく計算できそう。
このようにしてbase offsetとbase alignmentが決まるので、シェーダの中で

 Vertex3D v0 = vertices[0].v[0]

のようにして、vulkanからシェーダに渡しているデータの要素を取ってこれる。
ray tracingシェーダの場合、頂点の情報はraygen shaderから渡されない限り、各シェーダ(pixcelごと)が独自にbufferにアクセスする必要があるので、上記の拡張機能を利用できる。

参考リポジトリ

私が書いているサンプルコードは以下にあります。
GitHub - kodai731/Aqoole-Engine-Android-Vulkan-Rendering-Engine-: Android + Vulkan Rendering Engine