2024-12-28 14:41:19 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2025 Erico Nunes
|
|
|
|
|
*
|
|
|
|
|
* based on gl-shaders.c:
|
|
|
|
|
* Copyright 2012 Intel Corporation
|
|
|
|
|
* Copyright 2015,2019,2021 Collabora, Ltd.
|
|
|
|
|
* Copyright 2016 NVIDIA Corporation
|
|
|
|
|
* Copyright 2019 Harish Krupo
|
|
|
|
|
* Copyright 2019 Intel Corporation
|
|
|
|
|
* Copyright 2021 Advanced Micro Devices, Inc.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
* the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
|
* next paragraph) shall be included in all copies or substantial
|
|
|
|
|
* portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "vulkan-renderer.h"
|
|
|
|
|
#include "vulkan-renderer-internal.h"
|
|
|
|
|
|
|
|
|
|
/* const uint32_t vulkan_vertex_shader_surface[]; vulkan_vertex_shader_surface.vert */
|
|
|
|
|
#include "vulkan_vertex_shader_surface.spv.h"
|
|
|
|
|
|
|
|
|
|
/* const uint32_t vulkan_vertex_shader_texcoord[]; vulkan_vertex_shader_texcoord.vert */
|
|
|
|
|
#include "vulkan_vertex_shader_texcoord.spv.h"
|
|
|
|
|
|
|
|
|
|
/* const uint32_t vulkan_fragment_shader[]; vulkan_fragment_shader.frag */
|
|
|
|
|
#include "vulkan_fragment_shader.spv.h"
|
|
|
|
|
|
|
|
|
|
struct vertex {
|
|
|
|
|
float pos[2];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct vertex_tc {
|
|
|
|
|
float pos[2];
|
|
|
|
|
float texcoord[2];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct fs_specialization_consts {
|
|
|
|
|
uint32_t c_variant;
|
|
|
|
|
uint32_t c_input_is_premult;
|
2025-10-05 11:48:42 +02:00
|
|
|
uint32_t c_green_tint;
|
2024-12-28 14:41:19 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void create_graphics_pipeline(struct vulkan_renderer *vr,
|
|
|
|
|
const struct vulkan_pipeline_requirements *req,
|
|
|
|
|
struct vulkan_pipeline *pipeline)
|
|
|
|
|
{
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
|
VkShaderModule vs_module;
|
|
|
|
|
VkShaderModuleCreateInfo vs_shader_module_create_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
switch (req->texcoord_input) {
|
|
|
|
|
case SHADER_TEXCOORD_INPUT_ATTRIB:
|
|
|
|
|
vs_shader_module_create_info.codeSize = sizeof(vulkan_vertex_shader_texcoord),
|
|
|
|
|
vs_shader_module_create_info.pCode = (uint32_t *)vulkan_vertex_shader_texcoord;
|
|
|
|
|
break;
|
|
|
|
|
case SHADER_TEXCOORD_INPUT_SURFACE:
|
|
|
|
|
vs_shader_module_create_info.codeSize = sizeof(vulkan_vertex_shader_surface);
|
|
|
|
|
vs_shader_module_create_info.pCode = (uint32_t *)vulkan_vertex_shader_surface;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
weston_log("Invalid req->texcoord_input\n");
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vkCreateShaderModule(vr->dev, &vs_shader_module_create_info, NULL, &vs_module);
|
|
|
|
|
|
|
|
|
|
const struct fs_specialization_consts fsc = {
|
|
|
|
|
req->variant,
|
2025-10-05 11:48:42 +02:00
|
|
|
req->input_is_premult,
|
|
|
|
|
req->green_tint,
|
2024-12-28 14:41:19 +01:00
|
|
|
};
|
|
|
|
|
const VkSpecializationMapEntry fsc_entries[] = {
|
2025-10-05 11:34:39 +02:00
|
|
|
{ 0, offsetof(struct fs_specialization_consts, c_variant), sizeof(fsc.c_variant) },
|
|
|
|
|
{ 1, offsetof(struct fs_specialization_consts, c_input_is_premult), sizeof(fsc.c_input_is_premult) },
|
2025-10-05 11:48:42 +02:00
|
|
|
{ 2, offsetof(struct fs_specialization_consts, c_green_tint), sizeof(fsc.c_green_tint) },
|
2024-12-28 14:41:19 +01:00
|
|
|
};
|
|
|
|
|
const VkSpecializationInfo fs_specialization = {
|
|
|
|
|
.mapEntryCount = ARRAY_LENGTH(fsc_entries),
|
|
|
|
|
.pMapEntries = fsc_entries,
|
|
|
|
|
.dataSize = sizeof(fsc),
|
|
|
|
|
.pData = &fsc,
|
|
|
|
|
};
|
|
|
|
|
VkShaderModule fs_module;
|
|
|
|
|
const VkShaderModuleCreateInfo fs_shader_module_create_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
|
|
|
.codeSize = sizeof(vulkan_fragment_shader),
|
|
|
|
|
.pCode = (uint32_t *)vulkan_fragment_shader,
|
|
|
|
|
};
|
|
|
|
|
vkCreateShaderModule(vr->dev, &fs_shader_module_create_info, NULL, &fs_module);
|
|
|
|
|
|
|
|
|
|
const VkPipelineShaderStageCreateInfo vert_shader_stage_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
|
.module = vs_module,
|
|
|
|
|
.pName = "main",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineShaderStageCreateInfo frag_shader_stage_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
|
.module = fs_module,
|
|
|
|
|
.pSpecializationInfo = &fs_specialization,
|
|
|
|
|
.pName = "main",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineShaderStageCreateInfo shader_stages[] = {vert_shader_stage_info, frag_shader_stage_info};
|
|
|
|
|
|
|
|
|
|
// SHADER_TEXCOORD_INPUT_ATTRIB
|
|
|
|
|
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_attrib = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
|
|
|
.vertexBindingDescriptionCount = 1,
|
|
|
|
|
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
|
|
|
|
|
{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.stride = sizeof(struct vertex_tc),
|
|
|
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.vertexAttributeDescriptionCount = 2,
|
|
|
|
|
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
|
|
|
|
|
{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.location = 0,
|
|
|
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
|
|
|
.offset = offsetof(struct vertex_tc, pos),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.location = 1,
|
|
|
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
|
|
|
.offset = offsetof(struct vertex_tc, texcoord),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// SHADER_TEXCOORD_INPUT_SURFACE
|
|
|
|
|
const VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_surface = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
|
|
|
.vertexBindingDescriptionCount = 1,
|
|
|
|
|
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
|
|
|
|
|
{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.stride = sizeof(struct vertex),
|
|
|
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
.vertexAttributeDescriptionCount = 1,
|
|
|
|
|
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
|
|
|
|
|
{
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.location = 0,
|
|
|
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
|
|
|
.offset = offsetof(struct vertex, pos),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineVertexInputStateCreateInfo *pipeline_vertex_input_state_create_info;
|
|
|
|
|
|
|
|
|
|
switch (req->texcoord_input) {
|
|
|
|
|
case SHADER_TEXCOORD_INPUT_ATTRIB:
|
|
|
|
|
pipeline_vertex_input_state_create_info = &pipeline_vertex_input_attrib;
|
|
|
|
|
break;
|
|
|
|
|
case SHADER_TEXCOORD_INPUT_SURFACE:
|
|
|
|
|
pipeline_vertex_input_state_create_info = &pipeline_vertex_input_surface;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
weston_log("Invalid req->texcoord_input\n");
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const VkPipelineInputAssemblyStateCreateInfo input_assembly = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
|
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
|
|
|
|
|
.primitiveRestartEnable = VK_FALSE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineViewportStateCreateInfo viewport_state = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
|
|
|
.viewportCount = 1,
|
|
|
|
|
.scissorCount = 1,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineRasterizationStateCreateInfo rasterizer = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
|
|
|
.depthClampEnable = VK_FALSE,
|
|
|
|
|
.rasterizerDiscardEnable = VK_FALSE,
|
|
|
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
|
|
|
.lineWidth = 1.0f,
|
|
|
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
|
|
|
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
|
|
|
|
.depthBiasEnable = VK_FALSE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineMultisampleStateCreateInfo multisampling = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
|
|
|
.sampleShadingEnable = VK_FALSE,
|
|
|
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VkPipelineColorBlendAttachmentState color_blend_attachment = {
|
|
|
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
|
|
|
.blendEnable = VK_FALSE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (req->blend) {
|
|
|
|
|
color_blend_attachment.blendEnable = VK_TRUE;
|
|
|
|
|
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
|
|
|
color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
|
|
|
color_blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
|
color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
|
|
|
color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const VkPipelineColorBlendStateCreateInfo color_blending = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
|
|
|
.logicOpEnable = VK_FALSE,
|
|
|
|
|
.logicOp = VK_LOGIC_OP_COPY,
|
|
|
|
|
.attachmentCount = 1,
|
|
|
|
|
.pAttachments = &color_blend_attachment,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkDynamicState dynamic_states[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
|
|
|
|
const VkPipelineDynamicStateCreateInfo dynamic_state = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
|
|
|
.dynamicStateCount = ARRAY_LENGTH(dynamic_states),
|
|
|
|
|
.pDynamicStates = dynamic_states,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkPipelineLayoutCreateInfo pipeline_layout_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
|
|
|
.setLayoutCount = 1,
|
|
|
|
|
.pSetLayouts = &pipeline->descriptor_set_layout,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result = vkCreatePipelineLayout(vr->dev, &pipeline_layout_info, NULL, &pipeline->pipeline_layout);
|
|
|
|
|
check_vk_success(result, "vkCreatePipelineLayout");
|
|
|
|
|
|
|
|
|
|
const VkGraphicsPipelineCreateInfo pipeline_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
|
|
|
.stageCount = 2,
|
|
|
|
|
.pStages = shader_stages,
|
|
|
|
|
.pVertexInputState = pipeline_vertex_input_state_create_info,
|
|
|
|
|
.pInputAssemblyState = &input_assembly,
|
|
|
|
|
.pViewportState = &viewport_state,
|
|
|
|
|
.pRasterizationState = &rasterizer,
|
|
|
|
|
.pMultisampleState = &multisampling,
|
|
|
|
|
.pColorBlendState = &color_blending,
|
|
|
|
|
.pDynamicState = &dynamic_state,
|
|
|
|
|
.layout = pipeline->pipeline_layout,
|
|
|
|
|
.renderPass = req->renderpass,
|
|
|
|
|
.subpass = 0,
|
|
|
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result = vkCreateGraphicsPipelines(vr->dev, VK_NULL_HANDLE, 1, &pipeline_info, NULL, &pipeline->pipeline);
|
|
|
|
|
check_vk_success(result, "vkCreateGraphicsPipelines");
|
|
|
|
|
|
|
|
|
|
vkDestroyShaderModule(vr->dev, fs_module, NULL);
|
|
|
|
|
vkDestroyShaderModule(vr->dev, vs_module, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
create_descriptor_set_layout(struct vulkan_renderer *vr, struct vulkan_pipeline *pipeline)
|
|
|
|
|
{
|
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
|
|
const VkDescriptorSetLayoutBinding vs_ubo_layout_binding = {
|
|
|
|
|
.binding = 0,
|
|
|
|
|
.descriptorCount = 1,
|
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkDescriptorSetLayoutBinding fs_ubo_layout_binding = {
|
|
|
|
|
.binding = 1,
|
|
|
|
|
.descriptorCount = 1,
|
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkDescriptorSetLayoutBinding fs_sampler_layout_binding = {
|
|
|
|
|
.binding = 2,
|
|
|
|
|
.descriptorCount = 1,
|
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const VkDescriptorSetLayoutBinding bindings[] = {
|
|
|
|
|
vs_ubo_layout_binding,
|
|
|
|
|
fs_ubo_layout_binding,
|
|
|
|
|
fs_sampler_layout_binding,
|
|
|
|
|
};
|
|
|
|
|
const VkDescriptorSetLayoutCreateInfo layout_info = {
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
|
|
|
.bindingCount = ARRAY_LENGTH(bindings),
|
|
|
|
|
.pBindings = bindings,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
result = vkCreateDescriptorSetLayout(vr->dev, &layout_info, NULL, &pipeline->descriptor_set_layout);
|
|
|
|
|
check_vk_success(result, "vkCreateDescriptorSetLayout");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct vulkan_pipeline *
|
|
|
|
|
vulkan_pipeline_create(struct vulkan_renderer *vr,
|
|
|
|
|
const struct vulkan_pipeline_requirements *reqs)
|
|
|
|
|
{
|
|
|
|
|
struct vulkan_pipeline *pipeline = NULL;
|
|
|
|
|
|
|
|
|
|
pipeline = zalloc(sizeof *pipeline);
|
|
|
|
|
if (!pipeline) {
|
|
|
|
|
weston_log("could not create pipeline\n");
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_list_init(&pipeline->link);
|
|
|
|
|
pipeline->key = *reqs;
|
|
|
|
|
|
|
|
|
|
create_descriptor_set_layout(vr, pipeline);
|
|
|
|
|
|
|
|
|
|
create_graphics_pipeline(vr, reqs, pipeline);
|
|
|
|
|
|
|
|
|
|
wl_list_insert(&vr->pipeline_list, &pipeline->link);
|
|
|
|
|
|
|
|
|
|
return pipeline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
vulkan_pipeline_destroy(struct vulkan_renderer *vr, struct vulkan_pipeline *pipeline)
|
|
|
|
|
{
|
|
|
|
|
vkDestroyPipelineLayout(vr->dev, pipeline->pipeline_layout, NULL);
|
|
|
|
|
vkDestroyPipeline(vr->dev, pipeline->pipeline, NULL);
|
|
|
|
|
vkDestroyDescriptorSetLayout(vr->dev, pipeline->descriptor_set_layout, NULL);
|
|
|
|
|
wl_list_remove(&pipeline->link);
|
|
|
|
|
free(pipeline);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
vulkan_renderer_pipeline_list_destroy(struct vulkan_renderer *vr)
|
|
|
|
|
{
|
|
|
|
|
struct vulkan_pipeline *pipeline, *next_pipeline;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each_safe(pipeline, next_pipeline, &vr->pipeline_list, link)
|
|
|
|
|
vulkan_pipeline_destroy(vr, pipeline);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
vulkan_pipeline_requirements_cmp(const struct vulkan_pipeline_requirements *a,
|
|
|
|
|
const struct vulkan_pipeline_requirements *b)
|
|
|
|
|
{
|
|
|
|
|
return memcmp(a, b, sizeof(*a));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct vulkan_pipeline *
|
|
|
|
|
vulkan_renderer_get_pipeline(struct vulkan_renderer *vr,
|
|
|
|
|
const struct vulkan_pipeline_requirements *reqs)
|
|
|
|
|
{
|
|
|
|
|
struct vulkan_pipeline *pipeline;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(pipeline, &vr->pipeline_list, link) {
|
|
|
|
|
if (vulkan_pipeline_requirements_cmp(reqs, &pipeline->key) == 0)
|
|
|
|
|
return pipeline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pipeline = vulkan_pipeline_create(vr, reqs);
|
|
|
|
|
if (pipeline)
|
|
|
|
|
return pipeline;
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|