【Vulkan】BufferDeviceAddressを使ってデータアクセスを楽にしたい

10202 ワード

Buffer Device Address を使ってChitシェーダから頂点データにアクセスしてみます。

GLSL準備

GLSL側では以下の準備をします。

  • 必要な拡張機能を有効化する
  • 必要なアドレスを持たせる構造体 MeshAddress の配列を受け取る
  • buffer_reference を使って頂点配列を用意する
sample.rchit
#version 460
#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_scalar_block_layout : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_buffer_reference2 : require

struct MeshAddress
{
    uint64_t vertices;
    uint64_t indices;
};

struct Vertex
{
    vec3 pos;
};

layout(buffer_reference, scalar) buffer Vertices { Vertex v[]; };
layout(buffer_reference, scalar) buffer Indices { uvec3 i[]; };
layout(binding = 3) buffer Addresses { MeshAddress address[]; } addresses;

Vulkan準備

Vulkan側では以下の準備をします。

  • 必要な拡張機能を有効化する
  • vk::DeviceAddress を含む BufferAddress 構造体を作成する
  • 参照したいバッファのアドレスを入力する
  • BufferAddress 配列のバッファを作る
main.cpp
vk::PhysicalDeviceFeatures deviceFeatures;
deviceFeatures.shaderInt64 = true;

vk::PhysicalDeviceBufferDeviceAddressFeatures addressFeatures;
addressFeatures.bufferDeviceAddress = true;

struct BufferAddress
{
    vk::DeviceAddress vertices;
    vk::DeviceAddress indices;
};

std::vector<BufferAddress> addresses;
for(auto&& mesh: meshes){
  BufferAddress address;
  address.vertices = mesh.vertexBuffer.deviceAddress;
  address.indices = mesh.indexBuffer.deviceAddress;
  addresses.push_back(address);
}

Buffer addressBuffer{
  sizeof(BufferAddress) * addresses.size(), 
  vk::BufferUsageFlagBits::eStorageBuffer |
  vk::BufferUsageFlagBits::eShaderDeviceAddress };

descSet.update("Addresses", addressBuffer);

GLSLで使う

sample.rchit
MeshAddress address = addresses.address[gl_InstanceID];
Vertices vertices = Vertices(address.vertices);
Indices indices = Indices(address.indices);

uvec3 index = indices.i[gl_PrimitiveID];
Vertex v0 = vertices.v[index.x];
Vertex v1 = vertices.v[index.y];
Vertex v2 = vertices.v[index.z];

こんな感じでキレイに書けます。
おわり。