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

642 lines
27 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>
2025-05-12 22:48:01 +02:00
#include <meshoptimizer.h>
#include <metis.h>
2025-05-16 13:04:43 +02:00
#include <mutex>
2025-05-12 22:48:01 +02:00
#include <unordered_map>
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);
2025-04-11 18:15:39 +02:00
instanceData.clear(true);
instanceMeshData.clear(true);
rayTracingScene.clear(true);
transparentData.clear(true);
2024-06-09 12:20:04 +02:00
for (auto& mat : materialData) {
for (auto& inst : mat.instances) {
2025-04-11 18:15:39 +02:00
inst.instanceData.clear(true);
inst.instanceMeshData.clear(true);
inst.cullingOffsets.clear(true);
inst.rayTracingData.clear(true);
2024-06-07 09:19:47 +02:00
}
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-05-12 22:48:01 +02:00
const auto& data = registeredMeshes[mesh->id].meshData;
uint32 numMeshlets = data.meshletRange.size;
for (uint32 i = 0; i < (numMeshlets + Gfx::numMeshletsPerTask - 1) / Gfx::numMeshletsPerTask; ++i) {
MeshData chunkMeshData = data;
chunkMeshData.meshletRange = {
.offset = data.meshletRange.offset + i * Gfx::numMeshletsPerTask,
.size = std::min(numMeshlets - i * Gfx::numMeshletsPerTask, Gfx::numMeshletsPerTask),
};
2025-03-09 22:42:05 +01:00
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,
2025-05-12 22:48:01 +02:00
.meshData = chunkMeshData,
2025-03-09 22:42:05 +01:00
.cullingOffset = meshletOffset,
.rayTracingScene = mesh->blas,
});
} else { // opaque
matInstanceData.rayTracingData.add(mesh->blas);
matInstanceData.instanceData.add(inst);
2025-05-12 22:48:01 +02:00
matInstanceData.instanceMeshData.add(chunkMeshData);
2025-03-09 22:42:05 +01:00
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-05-12 22:48:01 +02:00
descriptorSet->updateBuffer(POSITIONS_NAME, 0, positionBuffer);
descriptorSet->updateBuffer(INDEXBUFFER_NAME, 0, indexBuffer);
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
}
2025-05-12 22:48:01 +02:00
Array<VertexData::MeshletGroup> VertexData::groupMeshlets(std::span<MeshletDescription> meshlets) {
auto groupWithAllMeshets = [&]() {
MeshletGroup group;
for (uint32 i = 0; i < meshlets.size(); i++) {
group.meshlets.add(i);
}
return Array{group};
};
if (meshlets.size() < 8) {
return groupWithAllMeshets();
}
struct MeshletEdge {
explicit MeshletEdge(size_t a, size_t b) : first(std::min(a, b)), second(std::max(a, b)) {}
bool operator==(const MeshletEdge& other) const = default;
const size_t first;
const size_t second;
};
struct MeshletEdgeHasher {
size_t operator()(const MeshletEdge& edge) const { return CRC::Calculate(&edge, sizeof(MeshletEdge), CRC::CRC_32()); }
};
std::unordered_map<MeshletEdge, Array<size_t>, MeshletEdgeHasher> edges2Meshlets;
std::unordered_map<size_t, Array<MeshletEdge>> meshlets2Edges;
for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); ++meshletIndex) {
const auto& meshlet = meshlets[meshletIndex];
auto getVertexIndex = [&](size_t index) {
return vertexIndices[meshlet.vertexIndices.offset + primitiveIndices[meshlet.primitiveIndices.offset + index]];
};
const size_t triangleCount = meshlet.primitiveIndices.size;
for (size_t triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex) {
for (size_t i = 0; i < 3; ++i) {
MeshletEdge edge{getVertexIndex(i + triangleIndex * 3), getVertexIndex(((i + 1) % 3) + triangleIndex * 3)};
edges2Meshlets[edge].add(meshletIndex);
meshlets2Edges[meshletIndex].emplace(edge);
}
}
}
std::erase_if(edges2Meshlets, [&](const auto& pair) { return pair.second.size() <= 1; });
if (edges2Meshlets.empty()) {
return groupWithAllMeshets();
}
idx_t vertexCount = meshlets.size();
idx_t ncon = 1;
idx_t nparts = meshlets.size() / 4;
assert(nparts > 1);
idx_t options[METIS_NOPTIONS];
METIS_SetDefaultOptions(options);
options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
options[METIS_OPTION_CCORDER] = 1;
Array<idx_t> partition;
partition.resize(vertexCount);
Array<idx_t> xadjacency;
xadjacency.reserve(vertexCount + 1);
Array<idx_t> edgeAdjacency;
Array<idx_t> edgeWeights;
for (size_t meshletIndex = 0; meshletIndex < meshlets.size(); ++meshletIndex) {
size_t startIndexInEdgeAdjacency = edgeAdjacency.size();
for (const auto& edge : meshlets2Edges[meshletIndex]) {
auto connectionsIter = edges2Meshlets.find(edge);
if (connectionsIter == edges2Meshlets.end()) {
continue;
}
const auto& connections = connectionsIter->second;
for (const auto& connectedMeshlet : connections) {
if (connectedMeshlet != meshletIndex) {
auto existingEdgeIter =
std::find(edgeAdjacency.begin() + startIndexInEdgeAdjacency, edgeAdjacency.end(), connectedMeshlet);
if (existingEdgeIter == edgeAdjacency.end()) {
edgeAdjacency.emplace(connectedMeshlet);
edgeWeights.emplace(1);
} else {
ptrdiff_t d = std::distance(edgeAdjacency.begin(), existingEdgeIter);
assert(d >= 0);
assert(d < edgeWeights.size());
edgeWeights[d]++;
}
}
}
}
xadjacency.add(startIndexInEdgeAdjacency);
}
xadjacency.add(edgeAdjacency.size());
assert(xadjacency.size() == meshlets.size() + 1);
assert(edgeAdjacency.size() == edgeWeights.size());
idx_t edgeCut;
int result = METIS_PartGraphKway(&vertexCount, &ncon, xadjacency.data(), edgeAdjacency.data(), nullptr, nullptr, edgeWeights.data(),
&nparts, nullptr, nullptr, options, &edgeCut, partition.data());
assert(result == METIS_OK);
Array<MeshletGroup> groups;
groups.resize(nparts);
for (size_t i = 0; i < meshlets.size(); ++i) {
idx_t partitionNumber = partition[i];
groups[partitionNumber].meshlets.add(i);
}
return groups;
}
void VertexData::loadMesh(MeshId id, Array<Vector> loadedPositions, Array<uint32> loadedIndices) {
2024-07-05 12:02:46 +02:00
std::unique_lock l(vertexDataLock);
2025-04-14 22:26:33 +02:00
RegisteredMesh& mesh = registeredMeshes[id];
2025-05-12 22:48:01 +02:00
MeshData& data = mesh.meshData;
2025-04-15 13:29:12 +02:00
2025-05-12 22:48:01 +02:00
// generate an LOD hierarchy for the given source mesh
// load LOD 0
2025-05-13 10:29:05 +02:00
size_t previousMeshletsStart = meshlets.size(); // todo:
2025-05-12 22:48:01 +02:00
loadMeshlets(id, loadedPositions, loadedIndices);
2025-04-15 13:29:12 +02:00
2025-05-12 22:48:01 +02:00
/* const int maxLod = 25;
for (int lod = 0; lod < maxLod; ++lod) {
float tLod = lod / (float)maxLod;
2025-04-15 13:29:12 +02:00
2025-05-12 22:48:01 +02:00
std::span<MeshletDescription> previousLevelMeshlets =
2025-05-13 10:29:05 +02:00
std::span{meshlets.data() + previousMeshletsStart, meshlets.size() - previousMeshletsStart};
2025-05-12 22:48:01 +02:00
if (previousLevelMeshlets.size() <= 1) {
return;
2025-03-09 22:42:05 +01:00
}
2025-05-12 22:48:01 +02:00
auto groups = groupMeshlets(previousLevelMeshlets);
2025-05-13 10:29:05 +02:00
const uint32 newMeshletStart = meshlets.size();
2025-05-12 22:48:01 +02:00
for (const auto& group : groups) {
2025-05-13 10:29:05 +02:00
previousLevelMeshlets = std::span{meshlets.data() + previousMeshletsStart, meshlets.size() - previousMeshletsStart};
2025-05-12 22:48:01 +02:00
Array<uint32> groupVertexIndices;
for (const auto& meshletIndex : group.meshlets) {
const auto& meshlet = meshlets[meshletIndex];
size_t start = groupVertexIndices.size();
2025-05-13 10:29:05 +02:00
groupVertexIndices.resize(start + meshlet.primitiveIndices.size * 3);
for (size_t j = 0; j < meshlet.primitiveIndices.size * 3; ++j) {
groupVertexIndices[j + start] = vertexIndices[meshlet.vertexIndices.offset + primitiveIndices[meshlet.primitiveIndices.offset + j]];
2025-05-12 22:48:01 +02:00
}
}
const float threshold = 0.5f;
size_t targetIndexCount = groupVertexIndices.size() * threshold;
2025-05-13 10:29:05 +02:00
float targetError = 0.9f * tLod + 0.01f * (1 - tLod);
2025-05-12 22:48:01 +02:00
uint32 options = meshopt_SimplifyLockBorder;
Array<uint32> simplifiedIndexBuffer;
simplifiedIndexBuffer.resize(groupVertexIndices.size());
float simplificationError = 0.f;
size_t simplifiedIndexCount = meshopt_simplify(
simplifiedIndexBuffer.data(), groupVertexIndices.data(), groupVertexIndices.size(), (float*)loadedPositions.data(),
loadedPositions.size(), sizeof(Vector), targetIndexCount, targetError, options, &simplificationError);
simplifiedIndexBuffer.resize(simplifiedIndexCount);
if (simplifiedIndexCount > 0) {
2025-05-13 10:29:05 +02:00
loadMeshlets(id, loadedPositions, simplifiedIndexBuffer);
for (size_t i = newMeshletStart; i < meshlets.size(); ++i) {
meshlets[i].lod = lod + 1;
}
previousMeshletsStart = newMeshletStart;
2025-05-12 22:48:01 +02:00
}
}
}*/
std::memcpy(positions.data() + mesh.vertexOffset, loadedPositions.data(), loadedPositions.size() * sizeof(Vector));
2024-06-20 21:57:26 +02:00
}
2025-04-15 13:29:12 +02:00
void VertexData::removeMesh(MeshId id) {
RegisteredMesh& removing = registeredMeshes[id];
uint32 meshletOffset = meshlets.size();
2025-04-14 16:03:16 +02:00
uint32 numMeshlets = 0;
2025-04-15 13:29:12 +02:00
uint32 vertexIndicesOffset = vertexIndices.size();
uint32 numVertexIndices = 0;
uint32 primitiveIndicesOffset = primitiveIndices.size();
uint32 numPrimitiveIndices = 0;
2025-05-12 22:48:01 +02:00
uint32 indicesOffset = removing.meshData.indicesRange.offset;
uint32 numIndices = removing.meshData.indicesRange.size;
const auto& data = removing.meshData;
meshletOffset = std::min(meshletOffset, data.meshletRange.offset);
numMeshlets += data.meshletRange.size;
for (uint32 m = 0; m < data.meshletRange.size; ++m) {
MeshletDescription& meshlet = meshlets[data.meshletRange.offset + m];
vertexIndicesOffset = std::min(vertexIndicesOffset, meshlet.vertexIndices.offset);
numVertexIndices += meshlet.vertexIndices.size;
primitiveIndicesOffset = std::min(primitiveIndicesOffset, meshlet.primitiveIndices.offset);
numPrimitiveIndices += meshlet.primitiveIndices.size;
2025-04-15 13:29:12 +02:00
}
2025-05-12 22:48:01 +02:00
2025-04-15 13:29:12 +02:00
for (auto& mesh : registeredMeshes) {
2025-05-12 22:48:01 +02:00
auto& data = mesh.meshData;
if (data.meshletRange.offset > meshletOffset) {
for (uint32 i = 0; i < data.meshletRange.size; ++i) {
MeshletDescription& m = meshlets[data.meshletRange.offset + i];
if (m.primitiveIndices.offset > primitiveIndicesOffset) {
m.primitiveIndices.offset -= numPrimitiveIndices;
}
if (m.vertexIndices.offset > vertexIndicesOffset) {
m.vertexIndices.offset -= numVertexIndices;
2025-04-15 13:29:12 +02:00
}
}
2025-05-12 22:48:01 +02:00
data.meshletRange.offset -= numMeshlets;
data.indicesRange.offset -= numIndices;
2025-04-15 13:29:12 +02:00
}
}
uint32 numMeshletsToMove = meshlets.size() - (meshletOffset + numMeshlets);
uint32 numVertexIndicesToMove = vertexIndices.size() - (vertexIndicesOffset + numVertexIndices);
uint32 numPrimitiveIndicesToMove = primitiveIndices.size() - (primitiveIndicesOffset + numPrimitiveIndices);
std::move(meshlets.begin() + meshletOffset + numMeshlets, meshlets.begin() + meshletOffset + numMeshlets + numMeshletsToMove,
meshlets.begin() + meshletOffset);
std::move(vertexIndices.begin() + vertexIndicesOffset + numVertexIndices,
vertexIndices.begin() + vertexIndicesOffset + numVertexIndices + numVertexIndicesToMove,
vertexIndices.begin() + vertexIndicesOffset);
std::move(primitiveIndices.begin() + primitiveIndicesOffset + numPrimitiveIndices,
2025-04-17 20:58:12 +02:00
primitiveIndices.begin() + primitiveIndicesOffset + numPrimitiveIndices + numPrimitiveIndicesToMove,
2025-04-15 13:29:12 +02:00
primitiveIndices.begin() + primitiveIndicesOffset);
2025-04-17 20:58:12 +02:00
uint32 numIndicesToMove = indices.size() - (indicesOffset + numIndices);
std::move(indices.begin() + indicesOffset + numIndices, indices.begin() + indicesOffset + numIndices + numIndicesToMove,
indices.begin() + indicesOffset);
2025-04-14 16:03:16 +02:00
}
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++};
2025-04-14 22:26:33 +02:00
registeredMeshes.add({
.vertexOffset = head,
.vertexCount = numVertices,
});
2024-07-05 12:02:46 +02:00
head += numVertices;
if (head > verticesAllocated) {
verticesAllocated = 2 * head; // double capacity
std::cout << "Resizing buffers to " << verticesAllocated << std::endl;
2025-05-12 22:48:01 +02:00
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);
2025-05-12 22:48:01 +02:00
Array<uint32> ind(registeredMeshes[id].meshData.indicesRange.size);
std::memcpy(ind.data(), indices.data() + registeredMeshes[id].meshData.indicesRange.offset,
registeredMeshes[id].meshData.indicesRange.size * sizeof(uint32));
Array<Vector> pos(registeredMeshes[id].vertexCount);
std::memcpy(pos.data(), positions.data() + registeredMeshes[id].vertexOffset, registeredMeshes[id].vertexCount * sizeof(Vector));
2024-07-18 11:45:56 +02:00
Serialization::save(buffer, ind);
2025-05-12 22:48:01 +02:00
Serialization::save(buffer, pos);
2024-07-18 11:45:56 +02:00
}
2024-09-07 11:15:47 +02:00
uint64 VertexData::deserializeMesh(MeshId id, ArchiveBuffer& buffer) {
2025-05-12 22:48:01 +02:00
Array<Vector> pos;
2024-07-18 11:45:56 +02:00
Array<uint32> ind;
Serialization::load(buffer, ind);
2025-05-12 22:48:01 +02:00
Serialization::load(buffer, pos);
loadMesh(id, pos, ind);
uint64 result = pos.size() * sizeof(Vector);
2024-08-07 21:19:33 +02:00
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
2025-04-08 23:18:50 +02:00
void VertexData::addVertexDataInstance(VertexData* vertexData) { vertexDataList.add(vertexData); }
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
2025-05-12 22:48:01 +02:00
// positions
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = POSITIONS_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
// indexBuffer
instanceDataLayout->addDescriptorBinding(Gfx::DescriptorBinding{
.name = INDEXBUFFER_NAME,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
});
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;
2025-04-14 22:26:33 +02:00
registeredMeshes.clear();
2024-07-05 12:02:46 +02:00
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-05-12 22:48:01 +02:00
const auto& md = getMeshData(id);
meshletCount += md.meshletRange.size;
2024-09-07 11:15:47 +02:00
return result;
2023-12-12 11:37:00 +01:00
}
2025-05-12 22:48:01 +02:00
void VertexData::resizeBuffers() { positions.resize(verticesAllocated); }
void VertexData::updateBuffers() {
positionBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = verticesAllocated * sizeof(Vector),
.data = (uint8*)positions.data(),
},
.usage = Gfx::SE_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR,
.name = "Positions",
});
}
void VertexData::loadMeshlets(MeshId id, const Array<Vector>& loadedPositions, const Array<uint32>& loadedIndices) {
// Array<uint32> optimizedIndices = indices;
// tipsifyIndexBuffer(indices, positions.size(), 25, optimizedIndices);
const float coneWeight = 0.0f;
const uint32 meshletOffset = meshlets.size();
const uint32 vertexOffset = vertexIndices.size();
const uint32 primitiveOffset = primitiveIndices.size();
const uint32 maxMeshlets = meshopt_buildMeshletsBound(loadedIndices.size(), Gfx::numVerticesPerMeshlet, Gfx::numPrimitivesPerMeshlet);
Array<meshopt_Meshlet> meshoptMeshlets;
meshoptMeshlets.resize(maxMeshlets);
Array<uint32> meshletVertexIndices;
Array<uint8> meshletTriangles;
meshletVertexIndices.resize(maxMeshlets * Gfx::numVerticesPerMeshlet);
2025-05-13 10:29:05 +02:00
meshletTriangles.resize(maxMeshlets * Gfx::numPrimitivesPerMeshlet * 3);
2025-05-12 22:48:01 +02:00
const uint32 meshletCount =
meshopt_buildMeshlets(meshoptMeshlets.data(), meshletVertexIndices.data(), meshletTriangles.data(), loadedIndices.data(),
loadedIndices.size(), (float*)loadedPositions.data(), loadedPositions.size(), sizeof(Vector),
Gfx::numVerticesPerMeshlet, Gfx::numPrimitivesPerMeshlet, coneWeight);
const meshopt_Meshlet& last = meshoptMeshlets[meshletCount - 1];
const uint32 vertexCount = last.vertex_offset + last.vertex_count;
2025-05-13 10:29:05 +02:00
const uint32 indexCount = last.triangle_offset + last.triangle_count * 3;
2025-05-12 22:48:01 +02:00
vertexIndices.resize(vertexOffset + vertexCount);
primitiveIndices.resize(primitiveOffset + indexCount);
meshlets.resize(meshletOffset + meshletCount);
std::memcpy(vertexIndices.data() + vertexOffset, meshletVertexIndices.data(), vertexCount * sizeof(uint32));
std::memcpy(primitiveIndices.data() + primitiveOffset, meshletTriangles.data(), indexCount * sizeof(uint8));
for (size_t i = 0; i < meshletCount; ++i) {
MeshletDescription& m = meshlets[meshletOffset + i];
m.vertexIndices = {
.offset = vertexOffset + meshoptMeshlets[i].vertex_offset,
.size = meshoptMeshlets[i].vertex_count,
};
m.primitiveIndices = {
.offset = primitiveOffset + meshoptMeshlets[i].triangle_offset,
.size = meshoptMeshlets[i].triangle_count,
};
2025-05-13 10:29:05 +02:00
m.indicesOffset = registeredMeshes[id].vertexOffset;
2025-05-12 22:48:01 +02:00
// todo: use meshopt for bb generation
m.bounding = AABB();
for (size_t j = 0; j < m.vertexIndices.size; ++j) {
m.bounding.adjust(loadedPositions[vertexIndices[meshoptMeshlets[i].vertex_offset + j]]);
}
}
registeredMeshes[id].meshData = MeshData{
.bounding = AABB(),
.meshletRange =
{
.offset = meshletOffset,
.size = meshletCount,
},
.indicesRange =
{
.offset = (uint32)indices.size(),
.size = (uint32)loadedIndices.size(),
},
};
// todo: in case of a index split for 16 bit, do something here
indices.resize(indices.size() + loadedIndices.size());
std::memcpy(indices.data() + registeredMeshes[id].meshData.indicesRange.offset, loadedIndices.data(),
loadedIndices.size() * sizeof(uint32));
}
2024-06-09 12:20:04 +02:00
VertexData::VertexData() : idCounter(0), head(0), verticesAllocated(0), dirty(false) {}