Created pipeline builder and wrapper
basalt::Pipeline is mainly just a wrapper around VkPipeline however there is no cast operator provided (yet)
This commit is contained in:
226
src/vulkan/basalt_pipeline.cpp
Normal file
226
src/vulkan/basalt_pipeline.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "vulkan/basalt_pipeline.h"
|
||||
#include <fstream>
|
||||
|
||||
basalt::PipelineBuilder::PipelineBuilder(basalt::Device& device, VkExtent2D extent, VkPipeline previous_pipeline) :
|
||||
shader_stages(MEMORY_TAG_CLASS_DYNARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||
shader_modules(MEMORY_TAG_CLASS_DYNARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||
colour_attachments(MEMORY_TAG_CLASS_DYNARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||
dynamic_states(MEMORY_TAG_CLASS_DYNARRAY | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY),
|
||||
device(device), previous_pipeline(previous_pipeline)
|
||||
{
|
||||
dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamic_state_ci.pNext = VK_NULL_HANDLE;
|
||||
dynamic_state_ci.flags = 0;
|
||||
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = (float)extent.width;
|
||||
viewport.width = (float)extent.height;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
scissor.offset = { 0,0 };
|
||||
scissor.extent = extent;
|
||||
|
||||
viewport_ci.pNext = VK_NULL_HANDLE;
|
||||
viewport_ci.flags = 0;
|
||||
viewport_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
|
||||
vertex_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertex_ci.pNext = VK_NULL_HANDLE;
|
||||
vertex_ci.flags = 0;
|
||||
vertex_ci.vertexBindingDescriptionCount = 0;
|
||||
vertex_ci.pVertexBindingDescriptions = VK_NULL_HANDLE;
|
||||
vertex_ci.vertexAttributeDescriptionCount = 0;
|
||||
vertex_ci.pVertexAttributeDescriptions = VK_NULL_HANDLE;
|
||||
|
||||
assembly_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
assembly_ci.pNext = VK_NULL_HANDLE;
|
||||
assembly_ci.flags = 0;
|
||||
assembly_ci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
assembly_ci.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
raster_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
raster_ci.pNext = VK_NULL_HANDLE;
|
||||
raster_ci.flags = 0;
|
||||
raster_ci.depthClampEnable = VK_FALSE;
|
||||
raster_ci.rasterizerDiscardEnable = VK_FALSE;
|
||||
raster_ci.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
raster_ci.lineWidth = 1.0f;
|
||||
raster_ci.cullMode = VK_CULL_MODE_BACK_BIT; // TODO: Change this
|
||||
raster_ci.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
raster_ci.depthBiasEnable = VK_FALSE;
|
||||
raster_ci.depthBiasConstantFactor = 0.0f;
|
||||
raster_ci.depthBiasClamp = 0.0f;
|
||||
raster_ci.depthBiasSlopeFactor = 0.0f;
|
||||
|
||||
multisample_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisample_ci.pNext = VK_NULL_HANDLE;
|
||||
multisample_ci.flags = 0;
|
||||
multisample_ci.sampleShadingEnable = VK_FALSE;
|
||||
multisample_ci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
multisample_ci.minSampleShading = 1.0f;
|
||||
multisample_ci.pSampleMask = VK_NULL_HANDLE;
|
||||
multisample_ci.alphaToCoverageEnable = VK_FALSE;
|
||||
multisample_ci.alphaToOneEnable = VK_FALSE;
|
||||
|
||||
colour_blend_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
colour_blend_ci.pNext = VK_NULL_HANDLE;
|
||||
colour_blend_ci.flags = 0;
|
||||
colour_blend_ci.logicOpEnable = VK_FALSE;
|
||||
colour_blend_ci.logicOp = VK_LOGIC_OP_COPY;
|
||||
colour_blend_ci.blendConstants[0] = 0.0f;
|
||||
colour_blend_ci.blendConstants[1] = 0.0f;
|
||||
colour_blend_ci.blendConstants[2] = 0.0f;
|
||||
colour_blend_ci.blendConstants[3] = 0.0f;
|
||||
|
||||
layout_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
layout_ci.pNext = VK_NULL_HANDLE;
|
||||
layout_ci.flags = 0;
|
||||
layout_ci.setLayoutCount = 0;
|
||||
layout_ci.pSetLayouts = nullptr;
|
||||
layout_ci.pushConstantRangeCount = 0;
|
||||
layout_ci.pPushConstantRanges = nullptr;
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder::~PipelineBuilder()
|
||||
{
|
||||
for (u32 i = 0; i < shader_modules.m_nelements; ++i)
|
||||
vkDestroyShaderModule(device, shader_modules[i], device.ctx->vk_alloc);
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder& basalt::PipelineBuilder::add_shader(const char* fpath, VkShaderStageFlagBits stage, const char* entry)
|
||||
{
|
||||
char* shader_src = nullptr;
|
||||
size_t shader_src_size = 0;
|
||||
read_file(fpath, shader_src, shader_src_size);
|
||||
this->shader_stages.push_back(VkPipelineShaderStageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.pNext = VK_NULL_HANDLE,
|
||||
.flags = 0,
|
||||
.stage = stage,
|
||||
.module = (VkShaderModule)this->shader_modules.m_nelements,
|
||||
.pName = entry,
|
||||
.pSpecializationInfo = VK_NULL_HANDLE
|
||||
});
|
||||
this->shader_modules.expand(this->shader_modules.m_nelements*2 + 1);
|
||||
VkShaderModuleCreateInfo ci = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||
ci.flags = 0;
|
||||
ci.codeSize = shader_src_size;
|
||||
ci.pCode = (uint32_t*)shader_src;
|
||||
ci.pNext = VK_NULL_HANDLE;
|
||||
|
||||
VkResult err = VK_SUCCESS;
|
||||
VK_ASSERT(vkCreateShaderModule(device, &ci, device.ctx->vk_alloc, this->shader_modules.end()), "Failed to create shader\n\tAt %s:%d\n\tError %s\n\tFor shader %s\n", fpath);
|
||||
this->shader_modules.m_nelements++;
|
||||
basalt::mem::dealloc(shader_src, shader_src_size, MEMORY_TAG_CLASS_STRING | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t basalt::PipelineBuilder::read_file(const char* fpath, char*& outptr, size_t& outptr_size)
|
||||
{
|
||||
std::ifstream f(fpath, std::ios::ate | std::ios::binary);
|
||||
if (!f.is_open())
|
||||
throw std::runtime_error("Failed to open file " + std::string(fpath));
|
||||
size_t fsz = static_cast<size_t>(f.tellg());
|
||||
if (outptr == nullptr || outptr_size < fsz)
|
||||
{
|
||||
if (outptr != nullptr)
|
||||
free(outptr);
|
||||
outptr = (char*)basalt::mem::alloc(fsz*sizeof(char), MEMORY_TAG_CLASS_STRING | MEMORY_TAG_ZONE_ENGINE | MEMORY_TAG_ALIGN_ANY);
|
||||
outptr_size = fsz;
|
||||
}
|
||||
f.seekg(0);
|
||||
f.read(outptr, fsz);
|
||||
f.close();
|
||||
return fsz;
|
||||
}
|
||||
|
||||
basalt::Pipeline::Pipeline(basalt::Device& device, VkPipeline pipeline, VkPipelineLayout layout) :
|
||||
device(&device), vk(pipeline), layout(layout)
|
||||
{}
|
||||
|
||||
basalt::Pipeline::~Pipeline()
|
||||
{
|
||||
if (this->should_free)
|
||||
{
|
||||
vkDestroyPipeline(*device, vk, device->ctx->vk_alloc);
|
||||
vkDestroyPipelineLayout(*device, layout, device->ctx->vk_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
basalt::Pipeline basalt::PipelineBuilder::build()
|
||||
{
|
||||
VkPipelineLayout layout = VK_NULL_HANDLE;
|
||||
// Create the pipeline layout
|
||||
VkResult err = VK_SUCCESS;
|
||||
VK_ASSERT(vkCreatePipelineLayout(device, &layout_ci, device.ctx->vk_alloc, &layout), "Failed to create pipeline layout\n\tAt %s:%d\n\tError %s\n");
|
||||
|
||||
for (u32 i = 0; i < shader_stages.m_nelements; ++i)
|
||||
shader_stages[i].module = shader_modules.m_pdata[(size_t)shader_stages[i].module];
|
||||
|
||||
dynamic_state_ci.dynamicStateCount = this->dynamic_states.m_nelements;
|
||||
dynamic_state_ci.pDynamicStates = this->dynamic_states.m_pdata;
|
||||
|
||||
viewport_ci.scissorCount = 1;
|
||||
viewport_ci.pScissors = &scissor;
|
||||
viewport_ci.viewportCount = 1;
|
||||
viewport_ci.pViewports = &viewport;
|
||||
|
||||
colour_blend_ci.attachmentCount = this->colour_attachments.m_nelements;
|
||||
colour_blend_ci.pAttachments = this->colour_attachments.m_pdata;
|
||||
|
||||
VkGraphicsPipelineCreateInfo ci = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
|
||||
ci.flags = VK_PIPELINE_CREATE_DERIVATIVE_BIT * (this->previous_pipeline != VK_NULL_HANDLE);
|
||||
ci.basePipelineHandle = this->previous_pipeline;
|
||||
ci.basePipelineIndex = -1;
|
||||
ci.stageCount = this->shader_stages.m_nelements;
|
||||
ci.pStages = this->shader_stages.m_pdata;
|
||||
ci.pVertexInputState = &vertex_ci;
|
||||
ci.pInputAssemblyState = &assembly_ci;
|
||||
ci.pViewportState = &viewport_ci;
|
||||
ci.pRasterizationState = &raster_ci;
|
||||
ci.pMultisampleState = &multisample_ci;
|
||||
ci.pDepthStencilState = VK_NULL_HANDLE;
|
||||
ci.pColorBlendState = &colour_blend_ci;
|
||||
ci.pDynamicState = &dynamic_state_ci;
|
||||
ci.layout = layout;
|
||||
ci.renderPass = render_pass;
|
||||
ci.subpass = 0;
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
VK_ASSERT(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &ci, device.ctx->vk_alloc, &pipeline), "Failed to create pipeline\n\tAt %s:%d\n\tError %s\n");
|
||||
|
||||
return basalt::Pipeline(device, pipeline, layout);
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder& basalt::PipelineBuilder::add_dynamic_state(const VkDynamicState state)
|
||||
{
|
||||
this->dynamic_states.push_back(state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder& basalt::PipelineBuilder::add_dynamic_states(const VkDynamicState* states, const u32 num_states)
|
||||
{
|
||||
this->dynamic_states.push_back(const_cast<VkDynamicState*>(states), num_states);
|
||||
return *this;
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder& basalt::PipelineBuilder::add_dynamic_states(const basalt::darray<VkDynamicState>& states)
|
||||
{
|
||||
this->dynamic_states.push_back(states);
|
||||
return *this;
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder& basalt::PipelineBuilder::set_render_pass(VkRenderPass render_pass)
|
||||
{
|
||||
this->render_pass = render_pass;
|
||||
return *this;
|
||||
}
|
||||
|
||||
basalt::PipelineBuilder& basalt::PipelineBuilder::add_colour_attachment(VkPipelineColorBlendAttachmentState attachment)
|
||||
{
|
||||
this->colour_attachments.push_back(attachment);
|
||||
return *this;
|
||||
}
|
||||
Reference in New Issue
Block a user