Files
Seele/src/Engine/Graphics/RenderPass/TerrainRenderer.cpp
T

319 lines
14 KiB
C++
Raw Normal View History

#include "TerrainRenderer.h"
#include "Asset/AssetRegistry.h"
#include "Component/TerrainTile.h"
#include "Graphics/Graphics.h"
2024-10-07 20:14:00 +02:00
#include "Graphics/Pipeline.h"
#include "Graphics/Shader.h"
using namespace Seele;
2024-10-07 20:14:00 +02:00
TerrainRenderer::TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout,
Gfx::PDescriptorSet viewParamsSet)
: graphics(graphics), scene(scene) {
2024-10-07 20:14:00 +02:00
meshUpdater.init(graphics, viewParamsLayout);
lebCache.init(graphics, 5);
CBT<21> cbt;
CPUMesh cpuMesh = generateCPUMesh(cbt.numElements());
plainMesh.gpuCBT.lastLevelSize = cbt.lastLevelSize();
for (uint32 i = 0; i < 2; ++i) {
uint32 bufferSize = cbt.bufferSize(i);
uint32 elementSize = cbt.elementSize(i);
plainMesh.gpuCBT.bufferArray[i] = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = bufferSize,
.data = (uint8*)cbt.rawBuffer(i),
},
.name = "GPUCBT",
});
plainMesh.gpuCBT.bufferArray[i]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
2024-09-29 22:28:37 +02:00
}
2024-10-07 20:14:00 +02:00
plainMesh.totalNumElements = cpuMesh.totalNumElements;
plainMesh.numBaseVertices = (uint32)cpuMesh.basePoints.size();
plainMesh.baseDepth = cpuMesh.minimalDepth;
plainMesh.heapIDBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
2024-09-29 22:28:37 +02:00
.sourceData =
{
2024-10-07 20:14:00 +02:00
.size = sizeof(uint64) * cpuMesh.totalNumElements,
.data = (uint8*)cpuMesh.heapIDArray.data(),
2024-09-29 22:28:37 +02:00
},
2024-10-07 20:14:00 +02:00
.name = "HeapID",
});
2024-10-07 20:14:00 +02:00
plainMesh.heapIDBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
2024-09-29 22:28:37 +02:00
2024-10-07 20:14:00 +02:00
plainMesh.currentNeighborsBufferIdx = 0;
plainMesh.neighborsBuffers[0] = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(UVector4) * cpuMesh.totalNumElements,
.data = (uint8*)cpuMesh.neighborsArray.data(),
},
.name = "Neighbours0",
});
2024-10-07 20:14:00 +02:00
plainMesh.neighborsBuffers[0]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
plainMesh.neighborsBuffers[1] = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(UVector4) * cpuMesh.totalNumElements,
},
.name = "Neighbours1",
});
2024-10-07 20:14:00 +02:00
plainMesh.neighborsBuffers[1]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
plainMesh.updateBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(BisectorData) * cpuMesh.totalNumElements,
},
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
.name = "UpdateBuffer",
2024-09-29 22:28:37 +02:00
});
2024-10-07 20:14:00 +02:00
plainMesh.classificationBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * (2 + cpuMesh.totalNumElements * 2),
},
.name = "Classification",
});
2024-10-07 20:14:00 +02:00
plainMesh.simplificationBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * (1 + cpuMesh.totalNumElements),
},
.name = "Simplification",
});
plainMesh.allocateBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * (1 + cpuMesh.totalNumElements),
},
.name = "Allocation",
});
plainMesh.propagateBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * (2 + cpuMesh.totalNumElements),
},
.name = "Propagate",
});
plainMesh.indirectDrawBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * (4 * 2 + 2),
},
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
.name = "IndirectDraw",
});
plainMesh.indirectDispatchBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * 3 * 3,
},
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
.name = "IndirectDispatch",
});
plainMesh.indexedBisectorBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * cpuMesh.totalNumElements,
},
.name = "IndexedBisector",
});
plainMesh.visibleIndexedBisectorBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * cpuMesh.totalNumElements,
},
.name = "VisibleIndexedBisector",
});
plainMesh.modifiedIndexedBisectorBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * cpuMesh.totalNumElements,
},
.name = "ModifiedIndexedBisector",
});
plainMesh.lebVertexBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(Vector4) * plainMesh.totalNumElements * 4,
},
.name = "LebVertexBuffer",
});
plainMesh.currentVertexBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(Vector4) * plainMesh.totalNumElements * 4,
},
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
.name = "CurrentVertexBuffer",
});
plainMesh.currentDisplacementBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(Vector4) * plainMesh.totalNumElements * 3,
},
.name = "CurrentDisplacementBuffer",
});
uint32 numBaseVertex = (uint32)cpuMesh.basePoints.size();
baseMesh.numVertices = numBaseVertex;
baseMesh.numElements = numBaseVertex / 3;
uint32 baseVertexBufferSize = sizeof(Vector4) * numBaseVertex;
baseMesh.vertexBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = baseVertexBufferSize,
.data = (uint8*)cpuMesh.basePoints.data(),
},
.name = "VertexBuffer",
});
baseMesh.vertexBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
uint32 indexBufferSize = cpuMesh.totalNumElements * sizeof(UVector);
Array<uint32> indices;
for (uint32 i = 0; i < cpuMesh.totalNumElements * 3; ++i)
indices.add(i);
baseMesh.indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * indices.size(),
.data = (uint8*)indices.data(),
},
.indexType = Gfx::SE_INDEX_TYPE_UINT32,
.name = "IndexBuffer",
});
baseMesh.indexBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
GeometryCB geometryCB = {
.totalNumElements = plainMesh.totalNumElements,
.baseDepth = plainMesh.baseDepth,
.totalNumVertices = plainMesh.totalNumElements * 3,
};
geometryBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{
.sourceData =
{
.size = sizeof(GeometryCB),
.data = (uint8*)&geometryCB,
},
.name = "GeometryCB",
});
geometryBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
UpdateCB updateCB = {
.triangleSize = 10.0f,
.maxSubdivisionDepth = 63,
.fov = 70.0f,
.farPlaneDistance = 1000.0f,
};
updateBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{
.sourceData =
{
.size = sizeof(UpdateCB),
.data = (uint8*)&updateCB,
},
.name = "UpdateCB",
});
updateBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT,
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
meshUpdater.resetBuffers(plainMesh);
meshUpdater.prepareIndirection(plainMesh, geometryBuffer);
meshUpdater.evaluateLeb(baseMesh, plainMesh, viewParamsSet, geometryBuffer, updateBuffer, lebCache.getLebMatrixBuffer(), true, true);
graphics->beginShaderCompilation(ShaderCompilationInfo{
.modules = {"TerrainPass"},
.entryPoints =
{
2024-10-07 20:14:00 +02:00
{"vert", "TerrainPass"},
{"frag", "TerrainPass"},
{"deform", "TerrainPass"},
},
2024-10-07 20:14:00 +02:00
.rootSignature = meshUpdater.pipelineLayout,
});
vert = graphics->createVertexShader({0});
frag = graphics->createFragmentShader({1});
deformCS = graphics->createComputeShader({2});
deform = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
.computeShader = deformCS,
.pipelineLayout = meshUpdater.pipelineLayout,
});
}
TerrainRenderer::~TerrainRenderer() {}
2024-10-07 20:14:00 +02:00
void TerrainRenderer::beginFrame(Gfx::PDescriptorSet viewParamsSet) {
meshUpdater.update(plainMesh, viewParamsSet, geometryBuffer, updateBuffer);
meshUpdater.evaluateLeb(baseMesh, plainMesh, viewParamsSet, geometryBuffer, updateBuffer, lebCache.getLebMatrixBuffer(), false, false);
Gfx::PDescriptorSet set = meshUpdater.layout->allocateDescriptorSet();
set->updateBuffer(GEOMETRY_CB, 0, geometryBuffer);
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, plainMesh.indirectDrawBuffer);
set->updateBuffer(INDEXED_BISECTOR_BUFFER, 0, plainMesh.indexedBisectorBuffer);
set->updateBuffer(LEB_POSITION_BUFFER, 0, plainMesh.lebVertexBuffer);
set->updateBuffer(CURRENT_VERTEX_BUFFER, 0, plainMesh.currentVertexBuffer);
set->writeChanges();
2024-10-07 20:14:00 +02:00
Gfx::OComputeCommand command = graphics->createComputeCommand("Deform");
command->bindPipeline(deform);
command->bindDescriptor({viewParamsSet, set});
command->dispatchIndirect(plainMesh.indirectDispatchBuffer, 3 * sizeof(uint32));
graphics->executeCommands(std::move(command));
plainMesh.currentVertexBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_VERTEX_SHADER_BIT);
}
Gfx::ORenderCommand TerrainRenderer::render(Gfx::PDescriptorSet viewParamsSet) {
2024-10-07 20:14:00 +02:00
Gfx::PDescriptorSet set = meshUpdater.layout->allocateDescriptorSet();
set->updateBuffer(CURRENT_VERTEX_BUFFER, 0, plainMesh.currentVertexBuffer);
set->updateBuffer(INDEXED_BISECTOR_BUFFER, 0, plainMesh.indexedBisectorBuffer);
set->writeChanges();
Gfx::ORenderCommand command = graphics->createRenderCommand("TerrainRender");
command->setViewport(viewport);
command->bindPipeline(pipeline);
command->bindDescriptor({viewParamsSet, set});
2024-10-07 20:14:00 +02:00
command->drawIndirect(plainMesh.indirectDrawBuffer, 0, 1, 0);
return command;
}
void TerrainRenderer::setViewport(Gfx::PViewport _viewport, Gfx::PRenderPass renderPass) {
viewport = _viewport;
2024-10-07 20:14:00 +02:00
inp = graphics->createVertexInput({});
Gfx::LegacyPipelineCreateInfo pipelineInfo = {
.vertexInput = inp,
.vertexShader = vert,
.fragmentShader = frag,
.renderPass = renderPass,
2024-10-07 20:14:00 +02:00
.pipelineLayout = meshUpdater.pipelineLayout,
.multisampleState =
{
.samples = viewport->getSamples(),
},
.rasterizationState =
{
//.polygonMode = Gfx::SE_POLYGON_MODE_LINE,
.cullMode = Gfx::SE_CULL_MODE_BACK_BIT,
},
.colorBlend =
{
.attachmentCount = 1,
.blendAttachments =
{
Gfx::ColorBlendState::BlendAttachment{
.blendEnable = false,
},
},
},
};
pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
2024-10-07 20:14:00 +02:00
}