feat: add forward+ rendering
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user