Разъяснение того, как расположены данные аргумента для вершинной функции, использующей MTLVertexDescriptor и атрибут [[attribute(n)]]

#swift #metal

#swift #Металлические

Вопрос:

Рассмотрим следующий MSL:

 #include <metal_stdlib>
using namespace metal;

struct VertexIn {
    float3 position     [[attribute(0)]];
    float3 normal       [[attribute(1)]];
    float3 color        [[attribute(2)]];
};

// Void just for demonstration
vertex void vertexFunc(const VertexIn vIn [[stage_in]]) {}
  

Концепция MTLBuffer объектов и MTLVertexDescriptor objects ясна: последнее описывает, как данные для металлической структуры ( VertexIn в данном случае) распределяются между различными MTLBuffer объектами. Затем, добавляя [[stage_in]] атрибут к аргументу в вершинную функцию с типом структуры, создается экземпляр с элементами структуры, соответствующими данным.

У меня есть один вопрос: [[stage_in]] автоматически ли выполняется смещение буфера на общий размер всех атрибутов с использованием определенного буфера ( totalSize ) totalSize * [[vertex_id]] внутри каждого MTLBuffer перед привязкой элементов структуры к данным с информацией о макете атрибута? Я полагаю, что это должно произойти, но я еще не нашел ничего, что указывало бы, происходит ли / как / когда это с [[stage_in]] .

Например, если мы использовали

 let descriptor = MTLVertexDescriptor()

// Position
descriptor.attributes[0].format = .float3
descriptor.attributes[0].bufferIndex = 0
descriptor.attributes[0].offset = 0

// Normal
descriptor.attributes[1].format = .float3
descriptor.attributes[1].bufferIndex = 0
descriptor.attributes[1].offset = MemoryLayout<vector_float3>.stride

// Color
descriptor.attributes[2].format = .float3
descriptor.attributes[2].bufferIndex = 1
descriptor.attributes[2].offset = 0

descriptor.layouts[0].stride = 2 * MemoryLayout<vector_float3>.stride
descriptor.layouts[1].stride = MemoryLayout<vector_float3>.stride
  

и установить два буфера, один с чередующимися позициями и обычными данными, а другой с цветовыми данными, будет ли вершинный шейдер получать данные n-й вершины (buffer0Start) n * (sizeof(float3) sizeof(float3)) в буфере 0 и (buffer1Start) n * (sizeof(float3)) в буфере 1 с [[stage_in]] ?

Ответ №1:

Похоже, что это так. Раздел 5.2.4, страница 87 «Спецификации языка металлического затенения» Apple версии 2.2 гласит

Вершинная функция может считывать входные данные для каждой вершины путем индексации в буфер (ы), переданный в качестве аргументов вершинной функции, используя идентификаторы вершины и экземпляра. Чтобы собрать входные данные для каждой вершины и передать их в качестве аргументов вершинной функции, объявите входные данные с [[stage_in]] атрибутом.