Vulkan API — урок 40.

Следующий шаг – определить UBO на стороне С++ и сказать Vulkan’у об этом дескрипторе в vertex shader.

struct UniformBufferObject {
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

Мы можем точно соответствовать определению в шейдере используя типы данных в GLM. Данные в матрицах двоичны и совместимы с шейдерами, так что мы можем в дальнейшем просто memcpy UniformBufferObject в VkBuffer.

Для создания конвейера нужно предоставить подробную информацию о каждом дескрипторе binding (привязка), используемом в шейдерах, так же как и для атрибутов вершин и их location индексов. Создадим функциюreateDescriptorSetLayout для определения всей этой информации. Она должна быть вызвана перед созданием конвейера.

void initVulkan() {
    ...
    createDescriptorSetLayout();
    createGraphicsPipeline();
    ...
}

...

void createDescriptorSetLayout() {

}

Каждый binding должен быть описан в структуре VkDescriptorSetLayoutBinding. Первые два поля определяют binding, используемый в шейдере и тип дескриптора, т.е. uniform buffer. Возможно, что дескриптор uniform buffer является массивом данных, и descriptorCount указывает количество значений в массиве. Это может быть использовано для указания преобразований для отдельных элементов единого, по сути, объекта.

void createDescriptorSetLayout() {
    VkDescriptorSetLayoutBinding uboLayoutBinding = {};
    uboLayoutBinding.binding = 0;
    uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
    uboLayoutBinding.descriptorCount = 1;
}

Так же понадобится указать, на какой шейдерный этап нужно ссылаться. Поле stageFlags может быть комбинацией флагов VkShaderStage или значением VK_SHADER_STAGE_ALL_GRAPHICS. В данный момент нужен только vertex shader.

uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;

Следующее поле нужно только для изображений, о чем позже. Можно оставить значение по умолчанию.

uboLayoutBinding.pImmutableSamplers = nullptr; // Optional

Все bindings дескрипторов объединяются в единый объект VkDescriptorSetLayout, определение которого должно быть выше pipelineLayout:

VDeleter<VkDescriptorSetLayout> descriptorSetLayout{device, vkDestroyDescriptorSetLayout};
VDeleter<VkPipelineLayout> pipelineLayout{device, vkDestroyPipelineLayout};

Далее создадим его используя vkCreateDescriptorSetLayout. Эта функция принимает просто VkDescriptorSetLayoutCreateInfo с массивом bindings:

VkDescriptorSetLayoutCreateInfo layoutInfo = {};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &uboLayoutBinding;

if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, descriptorSetLayout.replace()) != VK_SUCCESS) {
    throw std::runtime_error("failed to create descriptor set layout!");
}

Нам необходимо указать расположение набора дескрипторов при создании конвейера, что бы Vulkan понял, какие дескрипторы будут использовать шейдеры. Это указывается в полях layout конвейера. Добавим следующие изменения в VkPipelineLayoutCreateInfo:

VkDescriptorSetLayout setLayouts[] = {descriptorSetLayout};
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 1;
pipelineLayoutInfo.pSetLayouts = setLayouts;

Обратите внимание, что можно указывать несколько наборов дескрипторов. Но к этому через пару уроков. Следующие два урока будут так же посвящены настройке uniform buffer, на третий же мы увидим простейшее 3D.

Main Admin

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *