Aqoole_Hateenaの技術日記

vulkan+raytraceで色々描いてます

GL_EXT_nonuniform_qualifierについて

概要

vulkan + ray tracingのチュートリアルのコードを読んだときに気になっていた、GL_EXT_nonuniform_qualifierについて仕様の調査を行う。

仕様書

以下のGitHubが仕様書のようだ。
GLSL/GL_EXT_nonuniform_qualifier.txt at master · KhronosGroup/GLSL · GitHub

この仕様書内では以下のOpenGL Shading Language Specificationの仕様書を参照する。
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf

Overview

This extension adds a "nonuniform" type qualifier and constructor, which
is required by the Vulkan API to be used when indexing descriptor
bindings with an index that is not dynamically uniform.

This extension also allows arrays of resources declared using unsized
arrays to become run-time sized arrays.

とある。
nonuniformという修飾子を追加して、bindされるresourcesをdynamicに扱えるようにする。

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

例えばこのように、vulkan側ではレイアウトだけ定義しているresourcesをshader側でサイズの指定なしに宣言することができて

    Vertex3D v0 = vertices[nonuniformEXT(objId)].v[ind.x];

shader内ではこのようにしてresourcesにアクセスできる。
verticesを複数の要素からなる配列として扱える。

Vukan API側のextension

Vulkan APIを使用するプログラムの側でも拡張機能を使用する対応が必要。
VK_EXT_descriptor_indexing(3)

device_extensions.push_back("VK_EXT_descriptor_indexing");

のようにVK_EXT_descriptor_indexingの拡張機能を有効にする。

Description

This extension adds several small features which together enable applications to create large descriptor sets containing substantially all of their resources, and selecting amongst those resources with dynamic (non-uniform) indexes in the shader. There are feature enables and SPIR-V capabilities for non-uniform descriptor indexing in the shader, and non-uniform indexing in the shader requires use of a new NonUniformEXT decoration defined in the SPV_EXT_descriptor_indexing SPIR-V extension.

GLSLでの内容と同じことが記述されているが、shader内にてdescriptor setで渡すresourcesにdynamicにアクセスし、使用できる。

Section 4.1.9 Arrays

Section 4.1自体はGLSLでの基本となる型を定義している章となる。

仕様書のこの章としては、サイズが定義されていない場合の扱いについて、書き足すものとなる。
以下で今の仕様と異なっている箇所をピックアップする。

An array whose size is not specified in a declaration is _unsized_.
Unsized arrays can either be implicitly sized or run-time sized.
A _run-time sized_ array has its size determined by a buffer or
descriptor set bound via the API.

宣言時に全体のサイズを定義しない箇所が追記されている。
この場合は配列の最大indexでもってサイズが定義されるか、(vulkan)APIによってランタイムで定められる。

Unsized arrays must not be passed as an argument to a function,

unsized arrayは関数に引数として渡せない。

Section 4.x Nonuniform qualifier

nonuniformEXT qualifierが追加となる。
nonuniformEXT修飾子は変数や式がdynamic uniformでないときに使用する。

The nonuniformEXT qualifier can also be used with constructor syntax to
assert that an expression is not dynamically uniform. For example:

layout(location = 0) flat in int i;
layout(set = 0, binding = 0) uniform sampler2D tex[2];

color = texture(tex[nonuniformEXT(i)], ...);

This constructor syntax takes a single argument of any type and returns
the value with the same type, qualified with nonuniformEXT.

サンプルコード内にもあるような使い方としては以上が挙げられ、解説されている。