Фиксированные функции графического конвейера

Последнее обновление: 14.04.2025

(Практический пример по этой статье: Фиксированные функции графического конвейера в GLFW)

Часть этапов графического конвейера в Vulkan управляются фиксированными функциями.

Входные данные вершинных шейдеров

Структура VkPipelineVertexInputStateCreateInfo описывает формат данных вершин, которые будут переданы в вершинный шейдер:

typedef struct VkPipelineVertexInputStateCreateInfo {
    VkStructureType                             sType;
    const void*                                 pNext;
    uint32_t                                    vertexBindingDescriptionCount;
    const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
    uint32_t                                    vertexAttributeDescriptionCount;
    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
} VkPipelineVertexInputStateCreateInfo;

Структура определяет следующие поля:

  • sType: тип структуры, который должен представлять значение VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO.

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • vertexBindingDescriptionCount: количество описаний привязок вершин в поле pVertexBindingDescriptions

  • pVertexBindingDescriptions: указатель на массив структур VkVertexInputBindingDescription.

  • vertexAttributeDescriptionCount: количество описаний атрибутов вершин, предоставленных в поле pVertexAttributeDescriptions.

  • pVertexAttributeDescriptions: указатель на массив структур VkVertexInputAttributeDescription.

Таким образом, для описания вершин необходимо два компонента:

  • Привязки (структура VkVertexInputBindingDescription): интервал между данными и устанавливаются ли данные для вершины или для геометрии

  • Описания атрибутов (структура VkVertexInputBindingDescription): тип атрибутов, переданных в вершинный шейдер, с помощью какой привязки их загружать и по какому смещению

Пример описания формата вершин:

VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 0;      // количество привязок
vertexInputInfo.pVertexBindingDescriptions = nullptr; // необязательно
vertexInputInfo.vertexAttributeDescriptionCount = 0;    // количество описаний атрибутов
vertexInputInfo.pVertexAttributeDescriptions = nullptr; // необязательно

Ассемблер входных данных

Для установки параметров сборки входных данных конвейера применяется структура VkPipelineInputAssemblyStateCreateInfo:

typedef struct VkPipelineInputAssemblyStateCreateInfo {
    VkStructureType                            sType;
    const void*                                pNext;
    VkPrimitiveTopology                        topology;
    VkBool32                                   primitiveRestartEnable;
} VkPipelineInputAssemblyStateCreateInfo;

Поля структуры:

  • sType: тип структуры - значение VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO.

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • topology: значение перечисления VkPrimitiveTopology, которое определяет топологию примитива - какой тип геометрии будет нарисован из вершин

  • primitiveRestartEnable: указывает, следует ли подключить перезапуск сборки примитивов

Итак, поле topology управляет построением геометрического примитива и представляет перечисление VkPrimitiveTopology. ОТмечу его основные значения:

  • VK_PRIMITIVE_TOPOLOGY_POINT_LIST: отдельные точки из вершин

  • VK_PRIMITIVE_TOPOLOGY_LINE_LIST: линия из каждых 2 вершин без повторного использования

  • VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: конечная вершина каждой линии используется как начальная вершина для следующей линии

  • VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: треугольник из каждых 3 вершин без повторного использования

  • VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: вторая и третья вершина каждого треугольника используются как первые две вершины следующего треугольника

Другое поле - primitiveRestartEnable при установке в VK_TRUE позволяет разбить линии и треугольники в топологических режимах VK_PRIMITIVE_TOPOLOGY_[ТИП]_STRIP, используя специальный индекс 0xFFFF или 0xFFFFFFFF.

Например, определение входных данных для рисования треугольника выглядело бы следующим образом:

VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable = VK_FALSE;

Область просмотра и ножницы

Область просмотра представляет область буфера кадра, в которую будет визуализироваться вывод. Она представлена структурой VkViewport:

typedef struct VkViewport {
    float    x;
    float    y;
    float    width;
    float    height;
    float    minDepth;
    float    maxDepth;
} VkViewport;

Поля структуры описывают положение и размеры область просмотра:

  • x и y — верхний левый угол области просмотра (x,y).

  • width и height — ширина и высота области просмотра соответственно.

  • minDepth и maxDepth — диапазон глубины области просмотра.

Например:

VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float) swapChainExtent.width;
viewport.height = (float) swapChainExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;

Обычно область просмотра начинается в точке (0, 0) и растягивается по ширине и высоте. Здесь предполагается, что ширина и высота передаются через переменную swapChainExtent, которая хранит ширину и высоту изображений цепочки буферов.

Значения minDepth и maxDepth указывают диапазон значений глубины для использования в буфере кадра. Эти значения должны быть в диапазоне [0.0f, 1.0f], но minDepth может быть больше maxDepth. В большинстве случаев можно использовать стандартные значения - 0.0f и 1.0f.

Ножницы

Ножницы (scissors) определяют прямоугольную область, в которой фактически будут храниться пиксели. Ножницы представлены структурой VkRect2D

typedef struct VkRect2D {
    VkOffset2D    offset;
    VkExtent2D    extent;
} VkRect2D;

Тут всего два поля:

  • offset: смещение на изображении, которая попадает в прямоугольник. Представляет значение VkOffset2D

  • extent: значение VkExtent2D, которое определяет размеры прямоугольника.

Любые пиксели за пределами прямоугольников ножниц будут отброшены растеризатором. То есть ножницы фактически обрезают изображение.

Таким образом, если бы мы хотели рисовать во всем буфере кадра, мы бы указали прямоугольник-ножницы, который покрывает его полностью:

VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = swapChainExtent;

Для конфигурации области просмотра и ножниц применяется структура VkPipelineViewportStateCreateInfo:

typedef struct VkPipelineViewportStateCreateInfo {
    VkStructureType                       sType;
    const void*                           pNext;
    VkPipelineViewportStateCreateFlags    flags;
    uint32_t                              viewportCount;
    const VkViewport*                     pViewports;
    uint32_t                              scissorCount;
    const VkRect2D*                       pScissors;
} VkPipelineViewportStateCreateInfo;

Структура определяет следующие поля:

  • sType: тип структуры, должен представлять значение VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO.

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • flags: не используется, зарезервирован для будущего использования.

  • viewportCount: количество областей просмотра, используемых конвейером.

  • pViewports: указатель на массив структур VkViewport, определяющих преобразования области просмотра. Если состояние области просмотра динамическое, этот элемент игнорируется.

  • scissorCount: количество ножниц, которое должно соответствовать количеству областей просмотра.

  • pScissors: указатель на массив структур VkRect2D, определяющих прямоугольные границы ножниц для соответствующей области просмотра. Если состояние ножниц динамическое, этот элемент игнорируется.

Область просмотра и прямоугольники ножниц могут быть указаны либо как статическая часть конвейера, либо как динамическое состояние, установленное в буфере команд. При динамической установки области просмотра и ножниц необходимо включить соответствующие динамические состояния для конвейера с помощью структуры VkPipelineDynamicStateCreateInfo. Ее основные поля:

  • dynamicStateCount: количество элементов в массиве pDynamicStates.

  • pDynamicStates: указатель на массив значений VkDynamicState, указывающий, какие части состояния конвейера будут использовать значения из динамического состояния

Пример определения динамического состояния конвейера:

std::vector<VkDynamicState> dynamicStates = {
    VK_DYNAMIC_STATE_VIEWPORT,
    VK_DYNAMIC_STATE_SCISSOR
};

VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
dynamicState.pDynamicStates = dynamicStates.data();

А затем надо указать их количество во время создания конвейера:

VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.scissorCount = 1;

Фактические же область просмотра и ножницы будут настроены позднее во время рисования.

При определении области просмотра и ножниц как статической части конвейера их надо установить в конвейере с помощью структуры VkPipelineViewportStateCreateInfo:

VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;

Это делает область просмотра и прямоугольник ножниц для этого конвейера неизменяемыми. Любые изменения, требуемые для этих значений, потребуют создания нового конвейера с новыми значениями.

Растеризатор

Растеризатор (rasterizer) берет геометрию, сформированную вершинами из вершинного шейдера, и превращает ее во фрагменты, которые будут раскрашены фрагментным шейдером. Он также выполняет проверку глубины, отбраковку граней и т.д. Его можно настроить на вывод фрагментов, заполняющих целые полигоны или только края (каркасный рендеринг). Все это настраивается с помощью структуры VkPipelineRasterizationStateCreateInfo:

typedef struct VkPipelineRasterizationStateCreateInfo {
    VkStructureType                            sType;
    const void*                                pNext;
    VkPipelineRasterizationStateCreateFlags    flags;
    VkBool32                                   depthClampEnable;
    VkBool32                                   rasterizerDiscardEnable;
    VkPolygonMode                              polygonMode;
    VkCullModeFlags                            cullMode;
    VkFrontFace                                frontFace;
    VkBool32                                   depthBiasEnable;
    float                                      depthBiasConstantFactor;
    float                                      depthBiasClamp;
    float                                      depthBiasSlopeFactor;
    float                                      lineWidth;
} VkPipelineRasterizationStateCreateInfo;

Поля структуры:

  • sType: тип структуры, должен быть равен VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • flags: не используется и зарезервировано для будущего использования.

  • depthClampEnable управляет тем, следует ли фрагментам ограничивать значения глубины

    Если depthClampEnable установлено в VK_TRUE, то фрагменты, которые находятся за пределами ближней и дальней плоскостей, прикрепляются к ним, а не отбрасываются. Это полезно, например, для карт теней. Для использования этого требуется включение функции GPU.

  • rasterizerDiscardEnable: управляет тем, будут ли примитивы отбрасываться непосредственно перед этапом растеризации.

    Если rasterizerDiscardEnable установлен на VK_TRUE, то геометрия никогда не проходит через стадию растеризации. Это по сути отключает любой вывод в буфер кадра.

  • polygonMode: режим рендеринга треугольников. Представляет перечисление VkPolygonMode со следующими значениями:

    • VK_POLYGON_MODE_FILL: заполняет область полигона фрагментами

    • VK_POLYGON_MODE_LINE: ребра полигона рисуются как линии

    • VK_POLYGON_MODE_POINT: вершины полигона рисуются как точки

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

    • VK_CULL_MODE_NONE: ни один треугольник не отбрасывается

    • VK_CULL_MODE_FRONT_BIT: передние грани отбрасываются

    • VK_CULL_MODE_BACK_BIT: задние грани отбрасываются

    • VK_CULL_MODE_FRONT_AND_BACK: передние и задние грани отбрасываются

  • frontFace: определяет, является ли треугольник лицевой (обращен вперед) или тыльной стороной (обращен назад). Определяет порядок вершин для граней, которые следует считать обращенными вперед. Принимает следующие значения:

    • VK_FRONT_FACE_COUNTER_CLOCKWISE: треугольник с положительной площадью считается обращенным вперед.

    • VK_FRONT_FACE_CLOCKWISE: треугольник с отрицательной площадью считается обращенным вперед.

  • depthBiasEnable: управляет смещением значений глубины фрагмента

  • depthBiasConstantFactor: скалярный коэффициент, управляющий постоянным значением глубины, добавляемым к каждому фрагменту. Необязательное поле

  • depthBiasClamp: максимальный (или минимальный) сдвиг глубины фрагмента. Необязательное поле

  • depthBiasSlopeFactor: скалярный коэффициент, применяемый к наклону фрагмента при расчетах смещения глубины.

  • lineWidth: описывает толщину линий в терминах количества фрагментов. Максимальная поддерживаемая ширина линии зависит от оборудования, и любая линия толще 1.0f требует включения функции wideLines GPU.

Пример определения растеризатора:

VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f; // Необязательное поле
rasterizer.depthBiasClamp = 0.0f; // Необязательное поле
rasterizer.depthBiasSlopeFactor = 0.0f; // Необязательное поле

Мультисэмплинг

Мультисэмплинг (Multisampling) представляет один из способов сглаживания. Для его настройки применяется структура VkPipelineMultisampleStateCreateInfo:

typedef struct VkPipelineMultisampleStateCreateInfo {
    VkStructureType                          sType;
    const void*                              pNext;
    VkPipelineMultisampleStateCreateFlags    flags;
    VkSampleCountFlagBits                    rasterizationSamples;
    VkBool32                                 sampleShadingEnable;
    float                                    minSampleShading;
    const VkSampleMask*                      pSampleMask;
    VkBool32                                 alphaToCoverageEnable;
    VkBool32                                 alphaToOneEnable;
} VkPipelineMultisampleStateCreateInfo;

Поля структуры:

  • sType: тип структуры, должен быть равен VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • flags: не используется и зарезервировано для будущего использования.

  • rasterizationSamples: значение VkSampleCountFlagBits, указывающее количество выборок, используемых при растеризации. Принимает следующие значения:

    • VK_SAMPLE_COUNT_1_BIT: изображение с одним образцом на пиксель.

    • VK_SAMPLE_COUNT_2_BIT: изображение с 2 образцами на пиксель.

    • VK_SAMPLE_COUNT_4_BIT: изображение с 4 образцами на пиксель.

    • VK_SAMPLE_COUNT_8_BIT: изображение с 8 образцами на пиксель.

    • VK_SAMPLE_COUNT_16_BIT: изображение с 16 образцами на пиксель.

    • VK_SAMPLE_COUNT_32_BIT: изображение с 32 образцами на пиксель.

    • VK_SAMPLE_COUNT_64_BIT: изображение с 64 образцами на пиксель.

  • sampleShadingEnable: указывает, надо ли подключать технику Sample Shading.

  • minSampleShading: указывает на минимальную долю выборочной заливки, если sampleShadingEnable равно VK_TRUE.

  • pSampleMask: указатель на массив значений VkSampleMask, используемых в тесте маски выборки.

  • alphaToCoverageEnable: управляет тем, генерируется ли временное значение покрытия на основе альфа-компонента первого цветового вывода фрагмента

  • alphaToOneEnable управляет тем, заменяется ли альфа-компонент первого цветового вывода фрагмента.

Мультисэмплинг работает путем объединения результатов фрагментного шейдера, которые растеризуются в один и тот же пиксель. Это в основном происходит вдоль краев, где также возникают наиболее заметные артефакты сглаживания. Для его включения требуется включение функции GPU. Пример настройки мультисэмплинга:

VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampling.minSampleShading = 1.0f; // Необязательное поле
multisampling.pSampleMask = nullptr; // Необязательное поле
multisampling.alphaToCoverageEnable = VK_FALSE; // Необязательное поле
multisampling.alphaToOneEnable = VK_FALSE; // Необязательное поле

Цветовой переход Смешивание цветов

После того, как фрагментный шейдер возвратил цвет, его необходимо объединить с цветом, который уже находится в буфере кадра. Это преобразование известно как color blending или цветовой переход (еще называют смешиванием цветов). Для настройки цветового перехода есть два типа структур: VkPipelineColorBlendAttachmentState и VkPipelineColorBlendStateCreateInfo.

VkPipelineColorBlendAttachmentState

Структура VkPipelineColorBlendAttachmentState содержит конфигурацию для каждого прикрепленного буфера кадров

typedef struct VkPipelineColorBlendAttachmentState {
    VkBool32                 blendEnable;
    VkBlendFactor            srcColorBlendFactor;
    VkBlendFactor            dstColorBlendFactor;
    VkBlendOp                colorBlendOp;
    VkBlendFactor            srcAlphaBlendFactor;
    VkBlendFactor            dstAlphaBlendFactor;
    VkBlendOp                alphaBlendOp;
    VkColorComponentFlags    colorWriteMask;
} VkPipelineColorBlendAttachmentState;

Поля структуры:

  • blendEnable управляет включением смешивания для соответствующего цветового прикрепления. Цветовое прикрепление (color attachment) — это текстура, которая прикрепляется к буферу кадра в качестве цели рендеринга, используемой для внеэкранного рендеринга. Цветовые прикрепления используются в таких техниках, какотражение, преломление и отложенное затенение. И если смешивание не включено, цвет исходного фрагмента для этого прикрепления передается без изменений.

  • srcColorBlendFactor: выбирает, какой коэффициент смешивания используется для определения исходных факторов (Sr,Sg,Sb).

  • dstColorBlendFactor: выбирает, какой коэффициент смешивания используется для определения целевых факторов (Dr,Dg,Db).

  • colorBlendOp: выбирает, какая операция смешивания используется для расчета значений RGB для записи в цветовое прикрепление.

  • srcAlphaBlendFactor: выбирает, какой коэффициент смешивания используется для определения исходного фактора Sa.

  • dstAlphaBlendFactor: выбирает, какой коэффициент смешивания используется для определения целевого фактора Da.

  • alphaBlendOp: выбирает, какая операция смешивания используется для расчета значений альфа для записи в цветовое прикрепление.

  • colorWriteMask: битовая маска VkColorComponentFlagBits, указывающая, какие компоненты R, G, B и/или A разрешены для записи. Может принимать следующие значения:

    • VK_COLOR_COMPONENT_R_BIT указывает, что значение R записывается в цветовую вставку для соответствующего образца. В противном случае значение в памяти остается неизменным.

    • VK_COLOR_COMPONENT_G_BIT указывает, что значение G записывается в цветовую вставку для соответствующего образца. В противном случае значение в памяти остается неизменным.

    • VK_COLOR_COMPONENT_B_BIT указывает, что значение B записывается в цветовую вставку для соответствующего образца. В противном случае значение в памяти остается неизменным.

    • VK_COLOR_COMPONENT_A_BIT указывает, что значение A записывается в цветовую вставку для соответствующего образца. В противном случае значение в памяти остается неизменным.

Если blendEnable установлен в VK_FALSE, то новый цвет из фрагментного шейдера передается без изменений. В противном случае выполняются две операции смешивания для вычисления нового цвета. Результирующий цвет подвергается операции AND с colorWriteMask для определения того, какие каналы фактически передаются. Псевдокод смешения цветов:

if (blendEnable) {
    finalColor.rgb = (srcColorBlendFactor * newColor.rgb) <colorBlendOp> (dstColorBlendFactor * oldColor.rgb);
    finalColor.a = (srcAlphaBlendFactor * newColor.a) <alphaBlendOp> (dstAlphaBlendFactor * oldColor.a);
} else {
    finalColor = newColor;
}

finalColor = finalColor & colorWriteMask;

Где oldColor - старый цвет, newColor - новый цвет, finalColor - это финальный цвет, получаемый в результате смешения oldColor и newColor

ПРимер создания цветового перехода для одного буфера кадров:

VkPipelineColorBlendAttachmentState colorBlendAttachment{};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_FALSE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Необязательное поле
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Необязательное поле
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; // Необязательное поле
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Необязательное поле
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Необязательное поле
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; // Необязательное поле

Наиболее распространенный способ использования смешивания цветов — это реализация альфа-смешивания, когда мы хотим, чтобы новый цвет был смешан со старым цветом на основе его непрозрачности. Затем finalColor должен быть вычислен следующим образом:

finalColor.rgb = newAlpha * newColor + (1 - newAlpha) * oldColor;
finalColor.a = newAlpha.a;

Для этого мы можем настроить структуру следующим образом:

colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;

VkPipelineColorBlendStateCreateInfo

VkPipelineColorBlendStateCreateInfo определяет глобальные настройки смешивания цветов. Она ссылается на массив структур для всех буферов кадра и позволяет устанавливать константы смешивания, которые можно использовать в качестве факторов смешивания в вышеупомянутых вычислениях

typedef struct VkPipelineColorBlendStateCreateInfo {
    VkStructureType                               sType;
    const void*                                   pNext;
    VkPipelineColorBlendStateCreateFlags          flags;
    VkBool32                                      logicOpEnable;
    VkLogicOp                                     logicOp;
    uint32_t                                      attachmentCount;
    const VkPipelineColorBlendAttachmentState*    pAttachments;
    float                                         blendConstants[4];
} VkPipelineColorBlendStateCreateInfo;

Поля структуры:

  • sType: тип структуры, должен иметь значение VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO.

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • flags: битовая маска VkPipelineColorBlendStateCreateFlagBits, которая содержит дополнительную информацию для смешивания цветов.

  • logicOpEnable: управляет применением логических операций.

  • logicOp: выбирает, какую логическую операцию применять.

  • attachmentCount: количество элементов VkPipelineColorBlendAttachmentState в pAttachments.

  • pAttachments: указатель на массив структур VkPipelineColorBlendAttachmentState, которые определяют состояние смешивания для каждого цветового прикрепления.

  • blendConstants: указатель на массив из четырех цветовых компонентов R, G, B и A

ПРимер создания структуры:

VkPipelineColorBlendStateCreateInfo colorBlending{};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY; // Необязательное поле
colorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment; // ранее созданная структура VkPipelineColorBlendAttachmentState
colorBlending.blendConstants[0] = 0.0f; // Необязательное поле
colorBlending.blendConstants[1] = 0.0f; // Необязательное поле
colorBlending.blendConstants[2] = 0.0f; // Необязательное поле
colorBlending.blendConstants[3] = 0.0f; // Необязательное поле

Макет конвейера

Макет конвейреа позволяет определить некоторые константы для передачи динамических значений в шейдеры. Макет конвейера представляет непрозрачный указатель (opaque handle), для создания которого применяется функция vkCreatePipelineLayout:

VkResult vkCreatePipelineLayout(
    VkDevice                                    device,
    const VkPipelineLayoutCreateInfo*           pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
    VkPipelineLayout*                           pPipelineLayout);

В качестве параметров функция принимает:

  • device: логическое устройство, которое создает схему конвейера.

  • pCreateInfo: указатель на структуру VkPipelineLayoutCreateInfo, которая определяет конфигурацию макета конвейера.

  • pAllocator: аллокатор памяти хоста

  • pPipelineLayout: указатель на дескриптор VkPipelineLayout, в котором возвращается созданный макет конвейера.

Для создания макета необходима конфигурация, которая определяется структурой VkPipelineLayoutCreateInfo:

typedef struct VkPipelineLayoutCreateInfo {
    VkStructureType                 sType;
    const void*                     pNext;
    VkPipelineLayoutCreateFlags     flags;
    uint32_t                        setLayoutCount;
    const VkDescriptorSetLayout*    pSetLayouts;
    uint32_t                        pushConstantRangeCount;
    const VkPushConstantRange*      pPushConstantRanges;
} VkPipelineLayoutCreateInfo;

Поля структуры:

  • sType: тип структуры, должен иметь значение VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO.

  • pNext: NULL или указатель на структуру, расширяющую эту структуру.

  • flags: битовая маска VkPipelineLayoutCreateFlagBits, которая содержит параметры для создания макета конвейерав.

  • setLayoutCount: количество наборов дескрипторов, включенных в макет конвейера.

  • pSetLayouts: указатель на массив объектов VkDescriptorSetLayout.

  • pushConstantRangeCount: количество диапазонов констант, включенных в макет конвейера.

  • pPushConstantRanges: это указатель на массив структур VkPushConstantRange - набор диапазонов констант для использования в макете конвейера.

Пример создания макета конвейера:

VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0; // Необязательное поле
pipelineLayoutInfo.pSetLayouts = nullptr; // Необязательное поле
pipelineLayoutInfo.pushConstantRangeCount = 0; // Необязательное поле
pipelineLayoutInfo.pPushConstantRanges = nullptr; // Необязательное поле

if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
    throw std::runtime_error("Не удалось создать макет конвейера!");
}

После заврешения работы с макетом конвейера его надо удалить с помощью функции vkDestroyPipelineLayout():

void vkDestroyPipelineLayout(
    VkDevice                                    device,
    VkPipelineLayout                            pipelineLayout,
    const VkAllocationCallbacks*                pAllocator);

(Практический пример по этой статье: Фиксированные функции графического конвейера в GLFW)

Помощь сайту
Юмани:
410011174743222
Номер карты:
4048415020898850