1
0
Fork 0
Univerxel/src/client/render/vk/Pipeline.cpp

680 lines
34 KiB
C++

#include "Pipeline.hpp"
#include "PhysicalDeviceInfo.hpp"
#include "../../../core/data/file.hpp"
#include "../Renderer.hpp"
#include "api/Models.hpp"
#define CONTENT_DIR "content/"
#define SHADER_DIR CONTENT_DIR "shaders/"
using namespace render::vk;
Pipeline::Pipeline(VkDevice device, const PhysicalDeviceInfo &info, const render::renderOptions &options): device(device) {
const auto hasSamples = info.samples > 1;
{ // Render pass
VkAttachmentDescription colorAttachment{};
colorAttachment.format = info.getSurfaceFormat().format;
colorAttachment.samples = info.samples;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// NOTE: UI RenderPass do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0; //TODO: layouts bind
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription depthAttachment{};
depthAttachment.format = info.findDepthFormat();
depthAttachment.samples = info.samples;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentReference depthAttachmentRef{};
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkAttachmentDescription colorAttachmentResolve{};
colorAttachmentResolve.format = colorAttachment.format;
colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
// NOTE: UI RenderPass do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
VkAttachmentReference colorAttachmentResolveRef{};
colorAttachmentResolveRef.attachment = 2;
colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription colorDepthSubpass{};
colorDepthSubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
colorDepthSubpass.colorAttachmentCount = 1;
colorDepthSubpass.pColorAttachments = &colorAttachmentRef;
colorDepthSubpass.pDepthStencilAttachment = &depthAttachmentRef;
if (hasSamples) {
colorDepthSubpass.pResolveAttachments = &colorAttachmentResolveRef;
}
std::array<VkSubpassDescription, 4> subpasses = {colorDepthSubpass, colorDepthSubpass, colorDepthSubpass, colorDepthSubpass};
std::array<VkSubpassDependency, 7> dependencies{};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = 0;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = 0;
dependencies[1].srcSubpass = 0;
dependencies[1].dstSubpass = 1;
dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[2].srcSubpass = 0;
dependencies[2].dstSubpass = 1;
dependencies[2].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[2].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[2].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[2].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[2].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[3].srcSubpass = 1;
dependencies[3].dstSubpass = 2;
dependencies[3].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[3].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[3].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[3].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[3].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[4].srcSubpass = 1;
dependencies[4].dstSubpass = 2;
dependencies[4].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[4].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[4].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[4].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[4].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[5].srcSubpass = 2;
dependencies[5].dstSubpass = 3;
dependencies[5].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[5].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[5].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[5].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[5].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
dependencies[6].srcSubpass = 2;
dependencies[6].dstSubpass = 3;
dependencies[6].srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[6].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[6].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependencies[6].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependencies[6].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
std::vector<VkAttachmentDescription> attachments = {colorAttachment, depthAttachment};
if (hasSamples) {
attachments.push_back(colorAttachmentResolve);
}
renderPassInfo.attachmentCount = attachments.size();
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = subpasses.size();
renderPassInfo.pSubpasses = subpasses.data();
renderPassInfo.dependencyCount = dependencies.size();
renderPassInfo.pDependencies = dependencies.data();
if (vkCreateRenderPass(device, &renderPassInfo, ALLOC, &renderPass) != VK_SUCCESS) {
FATAL("Failed to create render pass!");
}
}
{ // UI Render pass
VkAttachmentDescription attachment = {};
attachment.format = info.getSurfaceFormat().format;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference color_attachment = {};
color_attachment.attachment = 0;
color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_attachment;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0; // or VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
info.dependencyCount = 1;
info.pDependencies = &dependency;
if (vkCreateRenderPass(device, &info, nullptr, &uiRenderPass) != VK_SUCCESS) {
FATAL("Failed to create UI render pass!");
}
}
//MAYBE: use sets (ubo, (samplers, passInfos))
//MAYBE: reuse sub UBO
{ // Voxel descriptor
std::array<VkDescriptorSetLayoutBinding, 4> bindings{};
bindings[0] = VoxelUBO::getLayoutBinding();
bindings[1].binding = 1;
bindings[1].descriptorCount = 1;
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[1].pImmutableSamplers = nullptr; //TODO: set immuable samplers
bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[2].binding = 2;
bindings[2].descriptorCount = 1;
bindings[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[2].pImmutableSamplers = nullptr;
bindings[2].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
bindings[3].binding = 3;
bindings[3].descriptorCount = 1;
bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bindings[3].pImmutableSamplers = nullptr;
bindings[3].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = bindings.size();
layoutInfo.pBindings = bindings.data();
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &voxelDescriptorSet) != VK_SUCCESS) {
FATAL("Failed to create descriptor set layout!");
}
}
{ // Indicator descriptor
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
auto binding = ViewProjUBO::getLayoutBinding();
layoutInfo.bindingCount = 1;
layoutInfo.pBindings = &binding;
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &indicDescriptorSet) != VK_SUCCESS) {
FATAL("Failed to create descriptor set layout!");
}
}
{ // Sky descriptor
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
samplerLayoutBinding.binding = 1;
samplerLayoutBinding.descriptorCount = 1;
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
samplerLayoutBinding.pImmutableSamplers = nullptr;
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
std::vector<VkDescriptorSetLayoutBinding> bindings = {ViewProjUBO::getLayoutBinding(), samplerLayoutBinding};
VkDescriptorSetLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = bindings.size();
layoutInfo.pBindings = bindings.data();
if (vkCreateDescriptorSetLayout(device, &layoutInfo, ALLOC, &skyDescriptorSet) != VK_SUCCESS) {
FATAL("Failed to create descriptor set layout!");
}
}
// Common pipeline settings
auto setShaders = [&](Subpass &pass, const std::string &shaderName, bool geometry = false, const VkSpecializationInfo* specialization = nullptr) -> std::vector<VkPipelineShaderStageCreateInfo>
{
auto createShaderModule = [&](const data::file_content &code) {
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size();
createInfo.pCode = reinterpret_cast<const uint32_t *>(code.data());
VkShaderModule shaderModule;
if (vkCreateShaderModule(device, &createInfo, ALLOC, &shaderModule) != VK_SUCCESS) {
FATAL("Failed to create shader module!");
}
return shaderModule;
};
VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
data::file_content vsFile({SHADER_DIR + shaderName + ".vs.spv"});
vertShaderStageInfo.module = pass.vsShader = createShaderModule(vsFile);
vertShaderStageInfo.pName = "main";
vertShaderStageInfo.pSpecializationInfo = specialization;
VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
data::file_content fsFile({SHADER_DIR + shaderName + ".fs.spv"});
fragShaderStageInfo.module = pass.fsShader = createShaderModule(fsFile);
fragShaderStageInfo.pName = "main";
fragShaderStageInfo.pSpecializationInfo = specialization;
if (geometry) {
VkPipelineShaderStageCreateInfo geomShaderStageInfo{};
geomShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
geomShaderStageInfo.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
data::file_content gsFile({SHADER_DIR + shaderName + ".gs.spv"});
geomShaderStageInfo.module = pass.gsShader = createShaderModule(gsFile);
geomShaderStageInfo.pName = "main";
geomShaderStageInfo.pSpecializationInfo = specialization;
return {vertShaderStageInfo, geomShaderStageInfo, fragShaderStageInfo};
} else {
return {vertShaderStageInfo, fragShaderStageInfo};
}
};
auto setLayout = [&](Subpass& pass, const std::vector<VkDescriptorSetLayout>& layout, const std::vector<VkPushConstantRange>& push = {}) {
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = layout.size();
pipelineLayoutInfo.pSetLayouts = layout.data();
pipelineLayoutInfo.pushConstantRangeCount = push.size();
pipelineLayoutInfo.pPushConstantRanges = push.data();
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, ALLOC, &pass.layout) != VK_SUCCESS) {
FATAL("Failed to create pipeline layout!");
}
};
VkPipelineDepthStencilStateCreateInfo depthStencil{};
depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencil.depthTestEnable = VK_TRUE;
depthStencil.depthWriteEnable = VK_TRUE;
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
depthStencil.depthBoundsTestEnable = VK_FALSE; // Restrict sub depth area
depthStencil.minDepthBounds = 0.0f;
depthStencil.maxDepthBounds = 1.0f;
depthStencil.stencilTestEnable = VK_FALSE;
// Stencil options front/back
VkPipelineColorBlendAttachmentState solidColorBlendAttachment{};
solidColorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
solidColorBlendAttachment.blendEnable = VK_FALSE;
VkPipelineColorBlendAttachmentState blendColorBlendAttachment{};
blendColorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendColorBlendAttachment.blendEnable = VK_TRUE;
blendColorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendColorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendColorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
blendColorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendColorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendColorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
VkPipelineColorBlendStateCreateInfo colorBlending{};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.attachmentCount = 1; //NOTE: For multitarget
colorBlending.pAttachments = options.voxel.transparency ? &blendColorBlendAttachment : &solidColorBlendAttachment;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY;
colorBlending.blendConstants[0] = 0.0f;
colorBlending.blendConstants[1] = 0.0f;
colorBlending.blendConstants[2] = 0.0f;
colorBlending.blendConstants[3] = 0.0f;
VkPipelineInputAssemblyStateCreateInfo trisInputAssembly{};
trisInputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
trisInputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
trisInputAssembly.primitiveRestartEnable = VK_FALSE;
// Viewport
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float)info.swapDetails.capabilities.currentExtent.width;
viewport.height = (float)info.swapDetails.capabilities.currentExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = {0, 0};
scissor.extent = info.swapDetails.capabilities.currentExtent;
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;
VkPipelineRasterizationStateCreateInfo rasterizer{};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = options.wireframe && info.features.fillModeNonSolid ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f;
rasterizer.depthBiasClamp = 0.0f;
rasterizer.depthBiasSlopeFactor = 0.0f;
VkPipelineMultisampleStateCreateInfo multisampling{};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.rasterizationSamples = info.samples;
//MAYBE: add option
multisampling.sampleShadingEnable = info.features.sampleRateShading && hasSamples;
multisampling.minSampleShading = .2f;
multisampling.pSampleMask = nullptr;
multisampling.alphaToCoverageEnable = VK_FALSE;
multisampling.alphaToOneEnable = VK_FALSE;
{ // World pipeline
VkPushConstantRange pushRange{};
pushRange.offset = 0;
pushRange.size = sizeof(UniqueCurvaturePush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(worldPass, {voxelDescriptorSet}, {pushRange});
struct SpeData {
bool fog;
bool pbr;
bool triplanar;
bool stochastic;
bool blend;
bool curvature;
bool curv_depth;
int32_t unitSize;
} speData;
std::array<VkSpecializationMapEntry, 8> speIndex;
speData.fog = options.voxel.fog;
speIndex[0].constantID = 0;
speIndex[0].offset = offsetof(SpeData, fog);
speIndex[0].size = sizeof(SpeData::fog);
speData.pbr = options.voxel.pbr;
speIndex[1].constantID = 1;
speIndex[1].offset = offsetof(SpeData, pbr);
speIndex[1].size = sizeof(SpeData::pbr);
speData.triplanar = options.voxel.triplanar;
speIndex[2].constantID = 2;
speIndex[2].offset = offsetof(SpeData, triplanar);
speIndex[2].size = sizeof(SpeData::triplanar);
speData.stochastic = options.voxel.stochastic;
speIndex[3].constantID = 3;
speIndex[3].offset = offsetof(SpeData, stochastic);
speIndex[3].size = sizeof(SpeData::stochastic);
speData.blend = options.voxel.blend;
speIndex[4].constantID = 4;
speIndex[4].offset = offsetof(SpeData, blend);
speIndex[4].size = sizeof(SpeData::blend);
speData.curvature = options.voxel.curvature;
speIndex[5].constantID = 5;
speIndex[5].offset = offsetof(SpeData, curvature);
speIndex[5].size = sizeof(SpeData::curvature);
speData.curv_depth = options.voxel.curv_depth;
speIndex[6].constantID = 6;
speIndex[6].offset = offsetof(SpeData, curv_depth);
speIndex[6].size = sizeof(SpeData::curv_depth);
speData.unitSize = 8; //TODO: load from world.voxel_density
speIndex[7].constantID = 16;
speIndex[7].offset = offsetof(SpeData, unitSize);
speIndex[7].size = sizeof(SpeData::unitSize);
VkSpecializationInfo specialization{};
specialization.dataSize = sizeof(SpeData);
specialization.pData = &speData;
specialization.mapEntryCount = speIndex.size();
specialization.pMapEntries = speIndex.data();
auto withGeometry = options.voxel.geometry && info.features.geometryShader;
auto shaderStages = setShaders(worldPass, withGeometry ? "Voxel.geo" : "Voxel", withGeometry, &specialization);
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Model::getBindingDescription();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
auto attributeDescriptions = Model::getAttributeDescriptions();
vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size();
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &trisInputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = worldPass.layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &worldPass.pipeline) != VK_SUCCESS) {
FATAL("Failed to create graphics pipeline!");
}
}
{ // Indicator pipeline
VkPushConstantRange pushRange{};
pushRange.offset = 0;
pushRange.size = sizeof(ModelColorPush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(indicPass, {indicDescriptorSet}, {pushRange});
auto shaderStages = setShaders(indicPass, "Color");
VkPipelineInputAssemblyStateCreateInfo lineInputAssembly{};
lineInputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
lineInputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
lineInputAssembly.primitiveRestartEnable = VK_FALSE;
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Shape::getBindingDescription();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
auto attributeDescription = Shape::getAttributeDescription();
vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = &attributeDescription;
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &lineInputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = indicPass.layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 1;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &indicPass.pipeline) != VK_SUCCESS) {
FATAL("Failed to create graphics pipeline!");
}
}
{ // Transparent World pipeline
VkPushConstantRange pushRange{};
pushRange.offset = 0;
pushRange.size = sizeof(UniqueCurvaturePush);
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
setLayout(transparentWorldPass, {voxelDescriptorSet}, {pushRange});
struct SpeData {
bool fog;
bool pbr;
bool triplanar;
bool stochastic;
bool blend;
bool curvature;
bool curv_depth;
int32_t unitSize;
} speData;
std::array<VkSpecializationMapEntry, 8> speIndex;
speData.fog = options.voxel.fog;
speIndex[0].constantID = 0;
speIndex[0].offset = offsetof(SpeData, fog);
speIndex[0].size = sizeof(SpeData::fog);
speData.pbr = options.voxel.pbr;
speIndex[1].constantID = 1;
speIndex[1].offset = offsetof(SpeData, pbr);
speIndex[1].size = sizeof(SpeData::pbr);
speData.triplanar = options.voxel.triplanar;
speIndex[2].constantID = 2;
speIndex[2].offset = offsetof(SpeData, triplanar);
speIndex[2].size = sizeof(SpeData::triplanar);
speData.stochastic = options.voxel.stochastic;
speIndex[3].constantID = 3;
speIndex[3].offset = offsetof(SpeData, stochastic);
speIndex[3].size = sizeof(SpeData::stochastic);
speData.blend = options.voxel.blend;
speIndex[4].constantID = 4;
speIndex[4].offset = offsetof(SpeData, blend);
speIndex[4].size = sizeof(SpeData::blend);
speData.curvature = options.voxel.curvature;
speIndex[5].constantID = 5;
speIndex[5].offset = offsetof(SpeData, curvature);
speIndex[5].size = sizeof(SpeData::curvature);
speData.curv_depth = options.voxel.curv_depth;
speIndex[6].constantID = 6;
speIndex[6].offset = offsetof(SpeData, curv_depth);
speIndex[6].size = sizeof(SpeData::curv_depth);
speData.unitSize = 8; //TODO: load from world.voxel_density
speIndex[7].constantID = 16;
speIndex[7].offset = offsetof(SpeData, unitSize);
speIndex[7].size = sizeof(SpeData::unitSize);
VkSpecializationInfo specialization{};
specialization.dataSize = sizeof(SpeData);
specialization.pData = &speData;
specialization.mapEntryCount = speIndex.size();
specialization.pMapEntries = speIndex.data();
auto withGeometry = options.voxel.geometry && info.features.geometryShader;
auto shaderStages = setShaders(transparentWorldPass, withGeometry ? "Voxel.geo" : "Voxel", withGeometry, &specialization);
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Model::getBindingDescription();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
auto attributeDescriptions = Model::getAttributeDescriptions();
vertexInputInfo.vertexAttributeDescriptionCount = attributeDescriptions.size();
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &trisInputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = transparentWorldPass.layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 2;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &transparentWorldPass.pipeline) != VK_SUCCESS) {
FATAL("Failed to create graphics pipeline!");
}
}
{ // Sky pipeline
setLayout(skyPass, {skyDescriptorSet}, {});
auto shaderStages = setShaders(skyPass, "Sky");
depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
auto bindingDescription = Shape::getBindingDescription();
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
auto attributeDescription = Shape::getAttributeDescription();
vertexInputInfo.vertexAttributeDescriptionCount = 1;
vertexInputInfo.pVertexAttributeDescriptions = &attributeDescription;
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = shaderStages.size();
pipelineInfo.pStages = shaderStages.data();
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &trisInputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = &depthStencil;
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = skyPass.layout;
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 3;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, ALLOC, &skyPass.pipeline) != VK_SUCCESS) {
FATAL("Failed to create graphics pipeline!");
}
}
}
Pipeline::~Pipeline() {
auto destroy = [&](Subpass &pass) {
if(pass.gsShader)
vkDestroyShaderModule(device, pass.gsShader, ALLOC);
vkDestroyShaderModule(device, pass.fsShader, ALLOC);
vkDestroyShaderModule(device, pass.vsShader, ALLOC);
vkDestroyPipeline(device, pass.pipeline, ALLOC);
vkDestroyPipelineLayout(device, pass.layout, ALLOC);
};
vkDestroyRenderPass(device, uiRenderPass, ALLOC);
destroy(worldPass);
destroy(indicPass);
destroy(skyPass);
vkDestroyDescriptorSetLayout(device, voxelDescriptorSet, ALLOC);
vkDestroyDescriptorSetLayout(device, indicDescriptorSet, ALLOC);
vkDestroyDescriptorSetLayout(device, skyDescriptorSet, ALLOC);
vkDestroyRenderPass(device, renderPass, ALLOC);
}