feat: add forward+ rendering

This commit is contained in:
2026-10-11 00:12:23 +02:00
parent c96b2282fb
commit 4bf87bd91b
26 changed files with 1346 additions and 191 deletions
+145 -60
View File
@@ -23,66 +23,122 @@ void MeshPipeline::init(
VkFormat drawImageFormat,
VkFormat depthImageFormat)
{
try {
const auto vertexShader =
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.vert");
try
{
const auto vertexShader =
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.vert");
const auto fragShader =
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.frag");
const auto fragShader =
AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.frag");
const auto bufferRange = VkPushConstantRange{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = 0,
.size = sizeof(PushConstants),
};
const auto bufferRange = VkPushConstantRange{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = 0,
.size = sizeof(PushConstants),
};
const auto pushConstantRanges = std::array{bufferRange};
const auto pushConstantRanges = std::array{bufferRange};
const auto layouts = std::array{
resources.getBindlessDescSetLayout()
};
const auto layouts = std::array{
resources.getBindlessDescSetLayout()
};
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = static_cast<std::uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount =
static_cast<std::uint32_t>(pushConstantRanges.size());
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = static_cast<std::uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount =
static_cast<std::uint32_t>(pushConstantRanges.size());
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
if (vkCreatePipelineLayout(
if (vkCreatePipelineLayout(
gfxDevice.getDevice(),
&pipelineLayoutInfo,
nullptr,
&m_pipelineLayout) != VK_SUCCESS)
{
throw std::runtime_error("Could not create mesh pipeline layout");
{
throw std::runtime_error("Could not create mesh pipeline layout");
}
{
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "Mesh Depth Prepass Pipeline";
pipelineConfig.pipelineLayout = m_pipelineLayout;
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.colorAttachments = {};
pipelineConfig.colorBlendInfo.attachmentCount = 0;
pipelineConfig.depthAttachment = depthImageFormat;
m_depthPrepassPipeline = std::make_unique<Pipeline>(
gfxDevice,
vertexShader.string(),
"",
pipelineConfig
);
}
{
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "Mesh Pipeline";
pipelineConfig.pipelineLayout = m_pipelineLayout;
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.colorAttachments = {drawImageFormat};
pipelineConfig.depthAttachment = depthImageFormat;
// depth was already written by the pre-pass, only shade the visible surface
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
m_pipeline = std::make_unique<Pipeline>(
gfxDevice,
vertexShader.string(),
fragShader.string(),
pipelineConfig
);
}
}
PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "Mesh Pipeline";
pipelineConfig.pipelineLayout = m_pipelineLayout;
pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.colorAttachments = {drawImageFormat};
pipelineConfig.depthAttachment = depthImageFormat;
m_pipeline = std::make_unique<Pipeline>(
gfxDevice,
vertexShader.string(),
fragShader.string(),
pipelineConfig
);
} catch (...) {
catch (...)
{
cleanup(gfxDevice.getDevice());
throw;
}
}
void MeshPipeline::drawDepthPrepass(
VkCommandBuffer cmd,
VkExtent2D renderExtent,
const RenderResources& resources,
const Camera& camera,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
{
if (!m_depthPrepassPipeline)
{
return;
}
drawMeshes(
cmd,
*m_depthPrepassPipeline,
renderExtent,
resources,
camera,
sceneDataBuffer,
drawCommands,
sortedDrawCommands);
}
void MeshPipeline::draw(
VkCommandBuffer cmd,
VkExtent2D renderExtent,
@@ -92,13 +148,35 @@ void MeshPipeline::draw(
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
{
if (!m_pipeline) {
if (!m_pipeline)
{
return;
}
drawMeshes(
cmd,
*m_pipeline,
renderExtent,
resources,
camera,
sceneDataBuffer,
drawCommands,
sortedDrawCommands);
}
void MeshPipeline::drawMeshes(
VkCommandBuffer cmd,
const Pipeline& pipeline,
VkExtent2D renderExtent,
const RenderResources& resources,
const Camera& camera,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
{
const MeshCache& meshCache = resources.meshes();
m_pipeline->bind(cmd);
pipeline.bind(cmd);
resources.bindBindlessDescSet(cmd, m_pipelineLayout);
@@ -130,8 +208,10 @@ void MeshPipeline::draw(
const auto frustum = edge::createFrustumFromCamera(camera);
const auto drawOne = [&](const MeshDrawCommand& dc) {
if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) {
const auto drawOne = [&](const MeshDrawCommand& dc)
{
if (!edge::isInFrustum(frustum, dc.worldBoundingSphere))
{
return;
}
@@ -139,7 +219,8 @@ void MeshPipeline::draw(
const auto& mesh = meshCache.getMesh(dc.meshId);
if (dc.meshId != prevMeshId) {
if (dc.meshId != prevMeshId)
{
prevMeshId = dc.meshId;
vkCmdBindIndexBuffer(
@@ -156,9 +237,9 @@ void MeshPipeline::draw(
.transform = dc.transformMatrix,
.sceneDataBuffer = sceneDataBuffer.address,
.vertexBuffer =
dc.skinnedMesh != nullptr
? dc.skinnedMesh->skinnedVertexBuffer.address
: mesh.vertexBuffer.address,
dc.skinnedMesh != nullptr
? dc.skinnedMesh->skinnedVertexBuffer.address
: mesh.vertexBuffer.address,
.materialId = dc.materialId,
.padding = 0,
};
@@ -175,26 +256,30 @@ void MeshPipeline::draw(
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
};
if (!sortedDrawCommands.empty()) {
for (std::size_t drawIndex : sortedDrawCommands) {
if (!sortedDrawCommands.empty())
{
for (std::size_t drawIndex : sortedDrawCommands)
{
assert(drawIndex < drawCommands.size());
drawOne(drawCommands[drawIndex]);
}
} else {
for (const MeshDrawCommand& dc : drawCommands) {
}
else
{
for (const MeshDrawCommand& dc : drawCommands)
{
drawOne(dc);
}
}
// Optional:
// spdlog::debug("Actual mesh draw calls: {}", actualDrawCalls);
}
void MeshPipeline::cleanup(VkDevice device)
{
m_pipeline.reset();
m_depthPrepassPipeline.reset();
if (m_pipelineLayout != VK_NULL_HANDLE && device != VK_NULL_HANDLE) {
if (m_pipelineLayout != VK_NULL_HANDLE && device != VK_NULL_HANDLE)
{
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
}
m_pipelineLayout = VK_NULL_HANDLE;