std140 – самый платформонезависимый лейаут uniform-блоков. Если вы передаете параметры в шейдер структурами, а не по одному, то лучше использовать именно его. Конечно, у переносимости есть своя цена: стандарт предусматривает несколько ограничений, самое известное из которых – выравнивание по 16 байтам. То есть, все поля структуры должны быть по размеру кратны 16 байтам. Например, если это вектор – то vec4, если матрица – то mat4. Некратные 16 байтам типы (float, int и др.) также можно использовать, но их необходимо выравнивать вручную – то есть, одиночный float пойдет все равно как vec4. Использование невыровненных данных приводит к тому, что в шейдере считываются неправильные значения, и это вызывает недоумение у начинающих.

Благодаря CTFE и статической интроспекции в D можно проверять структуры на соответствие этому правилу на этапе компиляции – все необходимое есть в std.traits:

import std.traits;

bool fieldsAligned(T, alias numBytes)()
{
    static if (is(T == struct))
    {
        alias FieldTypes = Fields!T;
        
        static foreach(FT; FieldTypes)
        {
            static if (FT.sizeof % numBytes != 0)
                return false;
        }
        
        return true;
    }
    else return false;
}

alias Std140Compliant(T) = fieldsAligned!(T, 16);

Теперь можно делать так:

import dlib.math.vector;
import dlib.math.matrix;

struct Uniforms
{
    Matrix4x4f modelViewMatrix;
    Matrix4x4f normalMatrix;
    Vector4f worldPosition;
    float someParameter; // Will not compile, use Vector4f instead
}

static assert(Std140Compliant!Uniforms,
    Uniforms.stringof ~ " does not conform to std140 layout");

Возникает вопрос, почему бы просто не делать align(16)? Можно!

struct AlignedUniforms
{
  align(16):
    float a;
    Vector3f b;
    Matrix4x4f c;
}

Преимуществом такого подхода является право использовать любые типы для полей, но это неэффктивно: например, вместо того, чтобы впустую расходовать три байта после a, можно было бы упаковать a вместе с b в один 16-байтный вектор. Поэтому я лично не фанат автоматического компиляторного выравнивания – лучше это делать вручную, защитившись от ошибок необходимыми статическими проверками.

Written by Gecko

Разработчик компьютерной графики

Оставить комментарий

Ваш адрес email не будет опубликован.