Files
Seele/src/Engine/Graphics/VertexData.cpp
T

360 lines
14 KiB
C++
Raw Normal View History

2023-10-24 15:01:09 +02:00
#include "VertexData.h"
2023-10-26 18:37:29 +02:00
#include "Graphics/Descriptor.h"
2024-06-09 12:20:04 +02:00
#include "Graphics/Enums.h"
#include "Graphics/Graphics.h"
#include "Graphics/Initializer.h"
2024-01-24 23:10:33 +01:00
#include "Graphics/Mesh.h"
2024-06-09 12:20:04 +02:00
#include "Graphics/Shader.h"
#include "Material/Material.h"
2024-06-09 10:44:24 +02:00
#include "Material/MaterialInstance.h"
#include <iostream>
2023-10-24 15:01:09 +02:00
using namespace Seele;
2024-10-07 20:14:00 +02:00
constexpr static uint64 NUM_DEFAULT_ELEMENTS = 36;
2024-06-07 09:19:47 +02:00
uint64 VertexData::meshletCount = 0;
2023-10-31 17:55:30 +01:00
2024-06-09 12:20:04 +02:00
void VertexData::resetMeshData() {
2024-06-07 09:19:47 +02:00
std::unique_lock l(materialDataLock);
2024-07-17 09:33:37 +02:00
instanceData.clear();
instanceMeshData.clear();
2024-07-10 21:07:10 +02:00
rayTracingScene.clear();
2024-07-17 10:40:40 +02:00
transparentData.clear();
2024-06-09 12:20:04 +02:00
for (auto& mat : materialData) {
for (auto& inst : mat.instances) {
2024-06-07 09:19:47 +02:00
inst.instanceData.clear();
inst.instanceMeshData.clear();
}
2024-06-09 12:20:04 +02:00
if (mat.material != nullptr) {
2024-06-07 09:19:47 +02:00
mat.material->getDescriptorLayout()->reset();
}
2023-11-17 18:46:37 +01:00
}
2024-06-09 12:20:04 +02:00
if (dirty) {
2024-06-07 09:19:47 +02:00
updateBuffers();
dirty = false;
2023-10-31 16:16:23 +01:00
}
2023-10-24 15:01:09 +02:00
}
2024-09-07 11:15:47 +02:00
void VertexData::updateMesh(uint32 meshletOffset, PMesh mesh, Component::Transform& transform) {
2024-06-07 09:19:47 +02:00
std::unique_lock l(materialDataLock);
PMaterialInstance referencedInstance = mesh->referencedMaterial->getHandle();
PMaterial mat = referencedInstance->getBaseMaterial();
2024-06-20 21:57:26 +02:00
Matrix4 transformMatrix = transform.toMatrix() * mesh->transform;
InstanceData inst = InstanceData{
.transformMatrix = transformMatrix,
.inverseTransformMatrix = glm::inverse(transformMatrix),
};
2024-07-17 09:33:37 +02:00
referencedInstance->updateDescriptor();
2024-06-09 12:20:04 +02:00
if (materialData.size() <= mat->getId()) {
2024-06-07 09:19:47 +02:00
materialData.resize(mat->getId() + 1);
}
2024-06-09 12:20:04 +02:00
MaterialData& matData = materialData[mat->getId()];
2024-06-07 09:19:47 +02:00
matData.material = mat;
2024-06-09 12:20:04 +02:00
if (matData.instances.size() <= referencedInstance->getId()) {
2024-06-07 09:19:47 +02:00
matData.instances.resize(referencedInstance->getId() + 1);
}
2024-06-09 12:20:04 +02:00
BatchedDrawCall& matInstanceData = matData.instances[referencedInstance->getId()];
2025-03-10 18:35:35 +01:00
matInstanceData.materialInstance = referencedInstance;
2025-03-09 22:42:05 +01:00
for (const auto& data : meshData[mesh->id]) {
if (mat->hasTransparency()) {
auto params = referencedInstance->getMaterialOffsets();
transparentData.add(TransparentDraw{
.matInst = referencedInstance,
.vertexData = this,
.offsets =
{
.instanceOffset = 0,
.textureOffset = params.textureOffset,
.samplerOffset = params.samplerOffset,
.floatOffset = params.floatOffset,
},
.worldPosition = Vector(inst.transformMatrix[3]),
.instanceData = inst,
.meshData = data,
.cullingOffset = meshletOffset,
.rayTracingScene = mesh->blas,
});
} else { // opaque
matInstanceData.rayTracingData.add(mesh->blas);
matInstanceData.instanceData.add(inst);
matInstanceData.instanceMeshData.add(data);
matInstanceData.cullingOffsets.add(meshletOffset);
}
}
2023-10-24 15:01:09 +02:00
}
2024-06-09 12:20:04 +02:00
void VertexData::createDescriptors() {
2024-06-07 09:19:47 +02:00
std::unique_lock l(materialDataLock);
2024-05-12 19:36:32 +02:00
2024-06-07 09:19:47 +02:00
Array<uint32> cullingOffsets;
2024-06-09 12:20:04 +02:00
for (auto& mat : materialData) {
for (auto& instance : mat.instances) {
2025-03-20 20:15:38 +01:00
instance.offsets.instanceOffset = (uint32)instanceData.size();
2024-06-18 19:19:05 +02:00
MaterialOffsets offsets = instance.materialInstance->getMaterialOffsets();
instance.offsets.textureOffset = offsets.textureOffset;
instance.offsets.samplerOffset = offsets.samplerOffset;
instance.offsets.floatOffset = offsets.floatOffset;
2024-06-09 12:20:04 +02:00
for (size_t i = 0; i < instance.instanceData.size(); ++i) {
2024-06-07 09:19:47 +02:00
cullingOffsets.add(instance.cullingOffsets[i]);
instanceData.add(instance.instanceData[i]);
instanceMeshData.add(instance.instanceMeshData[i]);
2024-07-10 21:07:10 +02:00
rayTracingScene.add(instance.rayTracingData[i]);
2024-06-07 09:19:47 +02:00
}
}
2024-05-12 19:36:32 +02:00
}
2024-07-18 11:45:56 +02:00
for (uint32 i = 0; i < transparentData.size(); ++i) {
2025-03-20 20:15:38 +01:00
transparentData[i].offsets.instanceOffset = (uint32)instanceData.size();
2024-07-19 10:42:59 +02:00
cullingOffsets.add(transparentData[i].cullingOffset);
2024-07-17 10:40:40 +02:00
instanceData.add(transparentData[i].instanceData);
instanceMeshData.add(transparentData[i].meshData);
rayTracingScene.add(transparentData[i].rayTracingScene);
}
2024-06-07 09:19:47 +02:00
cullingOffsetBuffer->rotateBuffer(cullingOffsets.size() * sizeof(uint32));
cullingOffsetBuffer->updateContents(0, cullingOffsets.size() * sizeof(uint32), cullingOffsets.data());
2024-06-09 12:20:04 +02:00
cullingOffsetBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_MEMORY_READ_BIT, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
2024-06-07 09:19:47 +02:00
instanceBuffer->rotateBuffer(instanceData.size() * sizeof(InstanceData));
instanceBuffer->updateContents(0, instanceData.size() * sizeof(InstanceData), instanceData.data());
2024-06-09 12:20:04 +02:00
instanceBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_MEMORY_READ_BIT,
Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
2024-06-07 09:19:47 +02:00
instanceMeshDataBuffer->rotateBuffer(sizeof(MeshData) * instanceMeshData.size());
instanceMeshDataBuffer->updateContents(0, sizeof(MeshData) * instanceMeshData.size(), instanceMeshData.data());
2024-06-09 12:20:04 +02:00
instanceMeshDataBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
Gfx::SE_ACCESS_MEMORY_READ_BIT, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
2024-06-20 21:57:26 +02:00
2024-06-07 09:19:47 +02:00
instanceDataLayout->reset();
descriptorSet = instanceDataLayout->allocateDescriptorSet();
2025-02-28 16:56:51 +09:00
descriptorSet->updateBuffer(INSTANCES_NAME, 0, instanceBuffer);
descriptorSet->updateBuffer(MESHDATA_NAME, 0, instanceMeshDataBuffer);
descriptorSet->updateBuffer(MESHLET_NAME, 0, meshletBuffer);
descriptorSet->updateBuffer(PRIMITIVEINDICES_NAME, 0, primitiveIndicesBuffer);
descriptorSet->updateBuffer(VERTEXINDICES_NAME, 0, vertexIndicesBuffer);
descriptorSet->updateBuffer(CULLINGOFFSETS_NAME, 0, cullingOffsetBuffer);
2024-06-18 19:19:05 +02:00
Material::updateDescriptor();
2023-11-10 19:18:09 +01:00
}
2024-06-09 12:20:04 +02:00
void VertexData::loadMesh(MeshId id, Array<uint32> loadedIndices, Array<Meshlet> loadedMeshlets) {
2024-07-05 12:02:46 +02:00
std::unique_lock l(vertexDataLock);
2025-03-10 18:35:35 +01:00
for (auto&& chunk : loadedMeshlets | std::views::chunk(2048)) {
2025-03-20 20:15:38 +01:00
uint32 meshletOffset = (uint32)meshlets.size();
2025-03-09 22:42:05 +01:00
AABB meshAABB;
2025-03-10 18:35:35 +01:00
uint32 numMeshlets = 0;
for (auto&& m : chunk) {
numMeshlets++;
2025-03-09 22:42:05 +01:00
//...
meshAABB = meshAABB.combine(m.boundingBox);
2025-03-20 20:15:38 +01:00
uint32 vertexOffset = (uint32)vertexIndices.size();
2025-03-09 22:42:05 +01:00
vertexIndices.resize(vertexOffset + m.numVertices);
std::memcpy(vertexIndices.data() + vertexOffset, m.uniqueVertices, m.numVertices * sizeof(uint32));
2025-03-20 20:15:38 +01:00
uint32 primitiveOffset = (uint32)primitiveIndices.size();
2025-03-09 22:42:05 +01:00
primitiveIndices.resize(primitiveOffset + (m.numPrimitives * 3));
std::memcpy(primitiveIndices.data() + primitiveOffset, m.primitiveLayout, m.numPrimitives * 3 * sizeof(uint8));
meshlets.add(MeshletDescription{
.bounding = m.boundingBox, //.toSphere(),
.vertexCount = m.numVertices,
.primitiveCount = m.numPrimitives,
.vertexOffset = vertexOffset,
.primitiveOffset = primitiveOffset,
.color = Vector((float)rand() / RAND_MAX, (float)rand() / RAND_MAX, (float)rand() / RAND_MAX),
.indicesOffset = (uint32)meshOffsets[id],
});
}
meshData[id].add(MeshData{
.bounding = meshAABB, //.toSphere(),
2025-03-10 18:35:35 +01:00
.numMeshlets = numMeshlets,
2025-03-09 22:42:05 +01:00
.meshletOffset = meshletOffset,
2024-07-05 12:02:46 +02:00
});
}
2025-03-09 22:42:05 +01:00
// todo: in case of a index split for 16 bit, do something here
meshData[id][0].firstIndex = (uint32)indices.size();
meshData[id][0].numIndices = (uint32)loadedIndices.size();
2024-07-05 12:02:46 +02:00
indices.resize(indices.size() + loadedIndices.size());
2025-03-09 22:42:05 +01:00
std::memcpy(indices.data() + meshData[id][0].firstIndex, loadedIndices.data(), loadedIndices.size() * sizeof(uint32));
2024-06-20 21:57:26 +02:00
}
void VertexData::commitMeshes() {
2024-07-05 12:02:46 +02:00
indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * indices.size(),
.data = (uint8*)indices.data(),
},
.indexType = Gfx::SE_INDEX_TYPE_UINT32,
.name = "IndexBuffer",
});
meshletBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(MeshletDescription) * meshlets.size(),
.data = (uint8*)meshlets.data(),
},
.numElements = meshlets.size(),
.name = "MeshletBuffer",
});
vertexIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * vertexIndices.size(),
.data = (uint8*)vertexIndices.data(),
},
.numElements = vertexIndices.size(),
.name = "VertexIndicesBuffer",
});
2024-07-05 12:02:46 +02:00
primitiveIndicesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint8) * primitiveIndices.size(),
.data = (uint8*)primitiveIndices.data(),
},
.numElements = primitiveIndices.size(),
.name = "PrimitiveIndicesBuffer",
});
2024-07-15 08:32:50 +02:00
updateBuffers();
dirty = false;
2024-12-25 14:59:08 +01:00
graphics->buildBottomLevelAccelerationStructures(std::move(dataToBuild));
2023-10-24 15:01:09 +02:00
}
2024-06-09 12:20:04 +02:00
MeshId VertexData::allocateVertexData(uint64 numVertices) {
2024-07-05 12:02:46 +02:00
std::unique_lock l(vertexDataLock);
MeshId res{idCounter++};
meshOffsets.add(head);
meshVertexCounts.add(numVertices);
meshData.add({});
head += numVertices;
if (head > verticesAllocated) {
verticesAllocated = 2 * head; // double capacity
std::cout << "Resizing buffers to " << verticesAllocated << std::endl;
2024-07-05 12:02:46 +02:00
resizeBuffers();
}
return res;
2023-10-31 17:55:30 +01:00
}
2025-03-09 22:42:05 +01:00
void VertexData::serializeMesh(MeshId id, ArchiveBuffer& buffer) {
2024-07-18 11:45:56 +02:00
std::unique_lock l(vertexDataLock);
Array<Meshlet> out;
2025-03-09 22:42:05 +01:00
for (uint32 n = 0; n < meshData[id].size(); ++n) {
MeshData data = meshData[id][n];
for (size_t i = 0; i < data.numMeshlets; ++i) {
MeshletDescription& desc = meshlets[i + data.meshletOffset];
Meshlet m;
std::memcpy(m.uniqueVertices, &vertexIndices[desc.vertexOffset], desc.vertexCount * sizeof(uint32));
std::memcpy(m.primitiveLayout, &primitiveIndices[desc.primitiveOffset], desc.primitiveCount * 3 * sizeof(uint8));
m.numPrimitives = desc.primitiveCount;
m.numVertices = desc.vertexCount;
m.boundingBox = desc.bounding;
out.add(std::move(m));
}
2024-07-18 11:45:56 +02:00
}
2025-03-09 22:42:05 +01:00
Array<uint32> ind(meshData[id][0].numIndices);
std::memcpy(ind.data(), &indices[meshData[id][0].firstIndex], meshData[id][0].numIndices * sizeof(uint32));
2024-07-18 11:45:56 +02:00
Serialization::save(buffer, out);
Serialization::save(buffer, ind);
}
2024-09-07 11:15:47 +02:00
uint64 VertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) {
2024-07-18 11:45:56 +02:00
Array<Meshlet> in;
Array<uint32> ind;
Serialization::load(buffer, in);
Serialization::load(buffer, ind);
loadMesh(id, ind, in);
2024-08-07 21:19:33 +02:00
uint64 result = in.size() * sizeof(MeshletDescription);
result += ind.size() * sizeof(uint32);
return result;
2024-07-18 11:45:56 +02:00
}
2024-06-09 12:20:04 +02:00
List<VertexData*> vertexDataList;
2023-10-24 15:01:09 +02:00
2024-07-05 12:02:46 +02:00
List<VertexData*> VertexData::getList() { return vertexDataList; }
2023-10-24 15:01:09 +02:00
2024-06-09 12:20:04 +02:00
VertexData* VertexData::findByTypeName(std::string name) {
2024-07-05 12:02:46 +02:00
for (auto vd : vertexDataList) {
if (vd->getTypeName() == name) {
return vd;
2024-06-07 09:19:47 +02:00
}
2024-07-05 12:02:46 +02:00
}
return nullptr;
2023-11-01 13:38:49 +01:00
}
2024-06-09 12:20:04 +02:00
void VertexData::init(Gfx::PGraphics _graphics) {
2024-07-05 12:02:46 +02:00
graphics = _graphics;
verticesAllocated = NUM_DEFAULT_ELEMENTS;
instanceDataLayout = graphics->createDescriptorLayout("pScene");
2023-11-26 09:40:48 +01:00
2024-07-05 12:02:46 +02:00
// instanceData
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
2025-02-28 16:56:51 +09:00
.name = INSTANCES_NAME,
2024-07-05 12:02:46 +02:00
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// meshData
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
2025-02-28 16:56:51 +09:00
.name = MESHDATA_NAME,
2024-07-05 12:02:46 +02:00
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// meshletData
2025-02-28 16:56:51 +09:00
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = MESHLET_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
2024-07-05 12:02:46 +02:00
// primitiveIndices
2025-02-28 16:56:51 +09:00
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = PRIMITIVEINDICES_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
2024-07-05 12:02:46 +02:00
// vertexIndices
2025-02-28 16:56:51 +09:00
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = VERTEXINDICES_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
2024-07-05 12:02:46 +02:00
// cullingOffset
2025-02-28 16:56:51 +09:00
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = CULLINGOFFSETS_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
2024-07-05 12:02:46 +02:00
// cullingInfos
2025-02-28 16:56:51 +09:00
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = CULLINGDATA_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
2024-07-05 12:02:46 +02:00
instanceDataLayout->create();
2024-06-07 09:19:47 +02:00
2024-07-05 12:02:46 +02:00
cullingOffsetBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.name = "MeshletOffset",
});
instanceBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.name = "InstanceBuffer",
});
instanceMeshDataBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.name = "MeshDataBuffer",
});
2024-08-08 22:53:49 +02:00
resizeBuffers();
2024-07-05 12:02:46 +02:00
graphics->getShaderCompiler()->registerVertexData(this);
2023-10-29 09:20:23 +01:00
}
2023-10-31 16:16:23 +01:00
2024-06-09 12:20:04 +02:00
void VertexData::destroy() {
2024-07-18 11:45:56 +02:00
cullingOffsetBuffer = nullptr;
2024-07-05 12:02:46 +02:00
instanceBuffer = nullptr;
instanceMeshDataBuffer = nullptr;
instanceDataLayout = nullptr;
meshletBuffer = nullptr;
vertexIndicesBuffer = nullptr;
primitiveIndicesBuffer = nullptr;
indexBuffer = nullptr;
meshData.clear();
materialData.clear();
2024-06-07 09:19:47 +02:00
}
2024-09-07 11:15:47 +02:00
uint32 VertexData::addCullingMapping(MeshId id) {
2025-03-20 20:15:38 +01:00
uint32 result = (uint32)meshletCount;
2025-03-09 22:42:05 +01:00
for (const auto& md : getMeshData(id)) {
meshletCount += md.numMeshlets;
}
2024-09-07 11:15:47 +02:00
return result;
2023-12-12 11:37:00 +01:00
}
2024-06-09 12:20:04 +02:00
VertexData::VertexData() : idCounter(0), head(0), verticesAllocated(0), dirty(false) {}