какие-нибудь более или менее универсальные best practices по передаче констант в шойдера в современных и не очень API?
Насколько я понимаю, самый распространенный и точно везде существующий вариант - это memcpy своей структуры в замапленный буфер, часто даже не один, а активный в цепочке нескольких буферов. Но как эти данные маппятся, особенно если хочется писать на переносимом и современном C++? Есть ли какие-нибудь надежные способы указать компилятору, что каждое поле занимает ровно сколько надо места, точно совпадает с принятым в API соглашением о выравниваниях и тд? Нет ли какой-нибудь классной библиотеки, чтобы не городить велосипеды?
Пользуется ли кто-то предоставляемой API рефлексией? Или обращение по именам вообще принципиально устарело?
Рефлексию можно получить через glslang, spirv-reflect или d3dreflect
ну, местами её и сами API предоставляют. Я сейчас перехожу со старичка OpenGL на Metal (и надеюсь пощупать D3D12/Vulkan, как появится побольше времени), так и в старичке были методы для запроса почти всей основной информации о том, какие переменные доступны шойдеру, так и в Metal есть класс MTArgument и возможность запроса этих аргументов при создании пайплайна (и ещё и некий ещё не щупанный ArgumentEncoder, который, как я понял, как раз умеет упаковывать почти все внутренние типы, включая непрозрачные, в буфер). Как я понимаю, в вулкане и D3D возможности компилировать на лету API не даёт, так что без либ не обойтись, но в общем-то в моем случае это пока даже не критично =) В общем, допустим, программу мы отрефлексировали тем или иным способом. А что дальше делать? У меня в старом коде был вот такой ужас: template <typename T, length_t C, length_t R, qualifier Q> void SetUniformInternal(GlUniformBuffer& buffer, const UniformBlockInfo& ubi, std::string_view name, const glm::mat<C, R, T, Q>& value) { const auto* ui = AT2::Utils::find(ubi.Uniforms, name); if (!ui) return; BufferMapperGuard mapping {buffer, static_cast<size_t>(ui->Offset), static_cast<size_t>(C) * ui->MatrixStride, BufferUsage::Write}; for (decltype(C) i = 0; i < C; ++i) mapping.Set(value[i], static_cast<size_t>(i) * ui->MatrixStride); } Неужели в новом придётся городить подобные конструкции? Всё это мало того что неэффективно, так ещё и как минимум несколько специализаций получается - вот для матриц, для массивов, для арифметических типов, для векторов... >_<
Компилировать на лету можно. Glslang умеет
да-да, это понятно. Раз оно для некоторых API аж в драйверы встроено, то скомпилять промежуточное представление и загрузить шейдер, конечно, можно везде. Я именно о маппинге данных в буфера.
Отдельные униформ переменные в современных апи не ставятся. Есть только униформ буфер. В старых апи под капотом эти переменные на самом деле тоже буфером отдельным были
кстати, похоже, что не совсем так - в Vulkan я нагуглил "push constants", которые хранятся в самом командном буфере, и в Metal тоже можно приаттачить массив байт вместо буфера в видео(точнее, общей, это ж Эпплы)памяти. Конечно, так или иначе оно тоже хранится в буфере, но при желании по одному параметры пропихивать, видимо, можно, хотя и понятно, что это не лучший вариант из возможных...
push constants - это другое и очень ограниченное по размеру.
куда push constants попадает очень различается на практике между разными дровами
Пуш констант не было в glsl/d11. У них самое больше ограничение - размер в 128 байт
а почему выше пишут что "это другое"? Я всё-таки не правильно понял, для чего эта штука нужна?
о, кстати, из этого вытекает небольшой вопрос про Вулкан вообще. Как вообще так получается, что компилятор соглашается принимать glsl с жестко выставленной версией 450 и, возможно, более младшие тоже? Ведь те же пуш-атрибуты помечаются как особый вариант uniform block (чем они и являются, как я понял, но в любом случае, это требует введения нового атрибута), обычные юниформы использовать, видимо, нельзя... Какой это нафиг 450, это же фактически новый диалект?!
Из спеки GLSL 4.6 When targeting Vulkan, the push_constant qualifier is used to declare an entire block, and represents a set of push constants, as defined by the Vulkan API
Обсуждают сегодня